PageRenderTime 51ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/src/runtime/base/shared/shared_variant.cpp

https://github.com/kevlund/hiphop-php
C++ | 486 lines | 430 code | 28 blank | 28 comment | 68 complexity | bb7eea7646e6216a1bd38b7ff2770663 MD5 | raw file
  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/base/shared/shared_variant.h>
  17. #include <runtime/ext/ext_variable.h>
  18. #include <runtime/ext/ext_apc.h>
  19. #include <runtime/base/shared/shared_map.h>
  20. #include <runtime/base/runtime_option.h>
  21. using namespace std;
  22. namespace HPHP {
  23. ///////////////////////////////////////////////////////////////////////////////
  24. SharedVariant::SharedVariant(CVarRef source, bool serialized,
  25. bool inner /* = false */,
  26. bool unserializeObj /* = false */)
  27. : m_count (1), m_shouldCache(false), m_flags(0){
  28. ASSERT(!serialized || source.isString());
  29. m_type = source.getType();
  30. switch (m_type) {
  31. case KindOfBoolean:
  32. {
  33. m_data.num = source.toBoolean();
  34. break;
  35. }
  36. case KindOfInt32:
  37. case KindOfInt64:
  38. {
  39. m_type = KindOfInt64;
  40. m_data.num = source.toInt64();
  41. break;
  42. }
  43. case KindOfDouble:
  44. {
  45. m_data.dbl = source.toDouble();
  46. break;
  47. }
  48. case KindOfStaticString:
  49. case KindOfString:
  50. {
  51. String s = source.toString();
  52. if (serialized) {
  53. m_type = KindOfObject;
  54. // It is priming, and there might not be the right class definitions
  55. // for unserialization.
  56. s = apc_reserialize(s);
  57. }
  58. m_data.str = s->copy(true);
  59. break;
  60. }
  61. case KindOfArray:
  62. {
  63. ArrayData *arr = source.getArrayData();
  64. if (!inner) {
  65. // only need to call hasInternalReference() on the toplevel array
  66. PointerSet seen;
  67. if (arr->hasInternalReference(seen)) {
  68. setSerializedArray();
  69. m_shouldCache = true;
  70. String s = apc_serialize(source);
  71. m_data.str = new StringData(s.data(), s.size(), CopyString);
  72. break;
  73. }
  74. }
  75. size_t size = arr->size();
  76. if (arr->isVectorData()) {
  77. setIsVector();
  78. m_data.vec = new VectorData(size);
  79. uint i = 0;
  80. for (ArrayIter it(arr); !it.end(); it.next(), i++) {
  81. SharedVariant* val = Create(it.secondRef(), false, true,
  82. unserializeObj);
  83. if (val->m_shouldCache) m_shouldCache = true;
  84. m_data.vec->vals[i] = val;
  85. }
  86. } else {
  87. m_data.map = new ImmutableMap(size);
  88. for (ArrayIter it(arr); !it.end(); it.next()) {
  89. SharedVariant* key = Create(it.first(), false, true,
  90. unserializeObj);
  91. SharedVariant* val = Create(it.secondRef(), false, true,
  92. unserializeObj);
  93. if (val->m_shouldCache) m_shouldCache = true;
  94. m_data.map->add(key, val);
  95. }
  96. }
  97. break;
  98. }
  99. case KindOfUninit:
  100. case KindOfNull:
  101. {
  102. break;
  103. }
  104. default:
  105. {
  106. ASSERT(source.isObject());
  107. m_shouldCache = true;
  108. if (unserializeObj) {
  109. // This assumes hasInternalReference(seen, true) is false
  110. ImmutableObj* obj = new ImmutableObj(source.getObjectData());
  111. m_data.obj = obj;
  112. setIsObj();
  113. } else {
  114. String s = apc_serialize(source);
  115. m_data.str = new StringData(s.data(), s.size(), CopyString);
  116. }
  117. break;
  118. }
  119. }
  120. }
  121. Variant SharedVariant::toLocal() {
  122. switch (m_type) {
  123. case KindOfBoolean:
  124. {
  125. return (bool)m_data.num;
  126. }
  127. case KindOfInt64:
  128. {
  129. return m_data.num;
  130. }
  131. case KindOfDouble:
  132. {
  133. return m_data.dbl;
  134. }
  135. case KindOfStaticString:
  136. {
  137. return m_data.str;
  138. }
  139. case KindOfString:
  140. {
  141. return NEW(StringData)(this);
  142. }
  143. case KindOfArray:
  144. {
  145. if (getSerializedArray()) {
  146. return apc_unserialize(String(m_data.str->data(), m_data.str->size(),
  147. AttachLiteral));
  148. }
  149. return NEW(SharedMap)(this);
  150. }
  151. case KindOfUninit:
  152. case KindOfNull:
  153. {
  154. return null_variant;
  155. }
  156. default:
  157. {
  158. ASSERT(m_type == KindOfObject);
  159. if (getIsObj()) {
  160. return m_data.obj->getObject();
  161. }
  162. return apc_unserialize(String(m_data.str->data(), m_data.str->size(),
  163. AttachLiteral));
  164. }
  165. }
  166. }
  167. void SharedVariant::dump(std::string &out) {
  168. out += "ref(";
  169. out += boost::lexical_cast<string>(m_count);
  170. out += ") ";
  171. switch (m_type) {
  172. case KindOfBoolean:
  173. out += "boolean: ";
  174. out += m_data.num ? "true" : "false";
  175. break;
  176. case KindOfInt64:
  177. out += "int: ";
  178. out += boost::lexical_cast<string>(m_data.num);
  179. break;
  180. case KindOfDouble:
  181. out += "double: ";
  182. out += boost::lexical_cast<string>(m_data.dbl);
  183. break;
  184. case KindOfStaticString:
  185. case KindOfString:
  186. out += "string(";
  187. out += boost::lexical_cast<string>(stringLength());
  188. out += "): ";
  189. out += stringData();
  190. break;
  191. case KindOfArray:
  192. if (getSerializedArray()) {
  193. out += "array: ";
  194. out += m_data.str->data();
  195. } else {
  196. SharedMap(this).dump(out);
  197. }
  198. break;
  199. case KindOfUninit:
  200. case KindOfNull:
  201. out += "null";
  202. break;
  203. default:
  204. out += "object: ";
  205. out += m_data.str->data();
  206. break;
  207. }
  208. out += "\n";
  209. }
  210. SharedVariant::~SharedVariant() {
  211. switch (m_type) {
  212. case KindOfObject:
  213. if (getIsObj()) {
  214. delete m_data.obj;
  215. break;
  216. }
  217. // otherwise fall through
  218. case KindOfString:
  219. m_data.str->destruct();
  220. break;
  221. case KindOfArray:
  222. {
  223. if (getSerializedArray()) {
  224. m_data.str->destruct();
  225. break;
  226. }
  227. if (getIsVector()) {
  228. delete m_data.vec;
  229. } else {
  230. delete m_data.map;
  231. }
  232. }
  233. break;
  234. default:
  235. break;
  236. }
  237. }
  238. ///////////////////////////////////////////////////////////////////////////////
  239. size_t SharedVariant::arrSize() const {
  240. ASSERT(is(KindOfArray));
  241. if (getIsVector()) return m_data.vec->size;
  242. return m_data.map->size();
  243. }
  244. int SharedVariant::getIndex(CVarRef key) {
  245. ASSERT(is(KindOfArray));
  246. switch (key.getType()) {
  247. case KindOfInt32:
  248. case KindOfInt64: {
  249. int64 num = key.getNumData();
  250. if (getIsVector()) {
  251. if (num < 0 || (size_t) num >= m_data.vec->size) return -1;
  252. return num;
  253. }
  254. return m_data.map->indexOf(num);
  255. }
  256. case KindOfStaticString:
  257. case KindOfString: {
  258. if (getIsVector()) return -1;
  259. StringData *sd = key.getStringData();
  260. return m_data.map->indexOf(sd);
  261. }
  262. default:
  263. // No other types are legitimate keys
  264. break;
  265. }
  266. return -1;
  267. }
  268. int SharedVariant::getIndex(CStrRef key) {
  269. ASSERT(is(KindOfArray));
  270. if (getIsVector()) return -1;
  271. StringData *sd = key.get();
  272. return m_data.map->indexOf(sd);
  273. }
  274. int SharedVariant::getIndex(litstr key) {
  275. ASSERT(is(KindOfArray));
  276. if (getIsVector()) return -1;
  277. StringData sd(key);
  278. return m_data.map->indexOf(&sd);
  279. }
  280. int SharedVariant::getIndex(int64 key) {
  281. ASSERT(is(KindOfArray));
  282. if (getIsVector()) {
  283. if (key < 0 || (size_t) key >= m_data.vec->size) return -1;
  284. return key;
  285. }
  286. return m_data.map->indexOf(key);
  287. }
  288. Variant SharedVariant::getKey(ssize_t pos) const {
  289. ASSERT(is(KindOfArray));
  290. if (getIsVector()) {
  291. ASSERT(pos < (ssize_t) m_data.vec->size);
  292. return pos;
  293. }
  294. return m_data.map->getKeyIndex(pos)->toLocal();
  295. }
  296. SharedVariant* SharedVariant::getValue(ssize_t pos) const {
  297. ASSERT(is(KindOfArray));
  298. if (getIsVector()) {
  299. ASSERT(pos < (ssize_t) m_data.vec->size);
  300. return m_data.vec->vals[pos];
  301. }
  302. return m_data.map->getValIndex(pos);
  303. }
  304. void SharedVariant::loadElems(ArrayData *&elems,
  305. const SharedMap &sharedMap,
  306. bool keepRef /* = false */) {
  307. ASSERT(is(KindOfArray));
  308. uint count = arrSize();
  309. bool isVector = getIsVector();
  310. ArrayInit ai(count, keepRef);
  311. for (uint i = 0; i < count; i++) {
  312. if (isVector) {
  313. ai.set(sharedMap.getValueRef(i));
  314. } else {
  315. ai.add(m_data.map->getKeyIndex(i)->toLocal(), sharedMap.getValueRef(i),
  316. true);
  317. }
  318. }
  319. elems = ai.create();
  320. if (elems->isStatic()) elems = elems->copy();
  321. }
  322. int SharedVariant::countReachable() const {
  323. int count = 1;
  324. if (getType() == KindOfArray) {
  325. int size = arrSize();
  326. if (!getIsVector()) {
  327. count += size; // for keys
  328. }
  329. for (int i = 0; i < size; i++) {
  330. SharedVariant* p = getValue(i);
  331. count += p->countReachable(); // for values
  332. }
  333. }
  334. return count;
  335. }
  336. SharedVariant *SharedVariant::Create
  337. (CVarRef source, bool serialized, bool inner /* = false */,
  338. bool unserializeObj /* = false*/) {
  339. SharedVariant *wrapped = source.getSharedVariant();
  340. if (wrapped && !unserializeObj) {
  341. wrapped->incRef();
  342. // static cast should be enough
  343. return (SharedVariant *)wrapped;
  344. }
  345. return new SharedVariant(source, serialized, inner, unserializeObj);
  346. }
  347. SharedVariant* SharedVariant::convertObj(CVarRef var) {
  348. if (!var.is(KindOfObject) || getObjAttempted()) {
  349. return NULL;
  350. }
  351. setObjAttempted();
  352. PointerSet seen;
  353. ObjectData *obj = var.getObjectData();
  354. if (obj->o_instanceof("Serializable")) {
  355. // should also check the object itself
  356. return NULL;
  357. }
  358. CArrRef arr = obj->o_toArray();
  359. if (arr->hasInternalReference(seen, true)) {
  360. return NULL;
  361. }
  362. SharedVariant *tmp = new SharedVariant(var, false, true, true);
  363. tmp->setObjAttempted();
  364. return tmp;
  365. }
  366. int32 SharedVariant::getSpaceUsage() {
  367. int32 size = sizeof(SharedVariant);
  368. if (!IS_REFCOUNTED_TYPE(m_type)) return size;
  369. switch (m_type) {
  370. case KindOfObject:
  371. if (getIsObj()) {
  372. return size + m_data.obj->getSpaceUsage();
  373. }
  374. // fall through
  375. case KindOfString:
  376. size += sizeof(StringData) + m_data.str->size();
  377. break;
  378. default:
  379. ASSERT(is(KindOfArray));
  380. if (getSerializedArray()) {
  381. size += sizeof(StringData) + m_data.str->size();
  382. } else if (getIsVector()) {
  383. size += sizeof(VectorData) +
  384. sizeof(SharedVariant*) * m_data.vec->size;
  385. for (size_t i = 0; i < m_data.vec->size; i++) {
  386. size += m_data.vec->vals[i]->getSpaceUsage();
  387. }
  388. } else {
  389. ImmutableMap *map = m_data.map;
  390. size += map->getStructSize();
  391. for (int i = 0; i < map->size(); i++) {
  392. size += map->getKeyIndex(i)->getSpaceUsage();
  393. size += map->getValIndex(i)->getSpaceUsage();
  394. }
  395. }
  396. break;
  397. }
  398. return size;
  399. }
  400. void SharedVariant::getStats(SharedVariantStats *stats) {
  401. stats->initStats();
  402. stats->variantCount = 1;
  403. switch (m_type) {
  404. case KindOfUninit:
  405. case KindOfNull:
  406. case KindOfBoolean:
  407. case KindOfInt64:
  408. case KindOfDouble:
  409. case KindOfStaticString:
  410. stats->dataSize = sizeof(m_data.dbl);
  411. stats->dataTotalSize = sizeof(SharedVariant);
  412. break;
  413. case KindOfObject:
  414. if (getIsObj()) {
  415. SharedVariantStats childStats;
  416. m_data.obj->getSizeStats(&childStats);
  417. stats->addChildStats(&childStats);
  418. break;
  419. }
  420. // fall through
  421. case KindOfString:
  422. stats->dataSize = m_data.str->size();
  423. stats->dataTotalSize = sizeof(SharedVariant) + sizeof(StringData) +
  424. stats->dataSize;
  425. break;
  426. default:
  427. ASSERT(is(KindOfArray));
  428. if (getSerializedArray()) {
  429. stats->dataSize = m_data.str->size();
  430. stats->dataTotalSize = sizeof(SharedVariant) + sizeof(StringData) +
  431. stats->dataSize;
  432. break;
  433. }
  434. if (getIsVector()) {
  435. stats->dataTotalSize = sizeof(SharedVariant) + sizeof(VectorData);
  436. stats->dataTotalSize += sizeof(SharedVariant*) * m_data.vec->size;
  437. for (size_t i = 0; i < m_data.vec->size; i++) {
  438. SharedVariant *v = m_data.vec->vals[i];
  439. SharedVariantStats childStats;
  440. v->getStats(&childStats);
  441. stats->addChildStats(&childStats);
  442. }
  443. } else {
  444. ImmutableMap *map = m_data.map;
  445. stats->dataTotalSize = sizeof(SharedVariant) + map->getStructSize();
  446. for (int i = 0; i < map->size(); i++) {
  447. SharedVariantStats childStats;
  448. map->getKeyIndex(i)->getStats(&childStats);
  449. stats->addChildStats(&childStats);
  450. map->getValIndex(i)->getStats(&childStats);
  451. stats->addChildStats(&childStats);
  452. }
  453. }
  454. break;
  455. }
  456. }
  457. ///////////////////////////////////////////////////////////////////////////////
  458. }