/runtime/arrays.c

https://github.com/pbiggar/phc · C · 426 lines · 323 code · 46 blank · 57 comment · 113 complexity · 1ec5a026b57de54de7fd8261b175f3ff MD5 · raw file

  1. // Extract the hashtable from a hash-valued zval
  2. static HashTable *
  3. extract_ht_ex (zval * arr TSRMLS_DC)
  4. {
  5. // TODO: this likely should be inlined somewhere.
  6. assert (!in_copy_on_write (arr));
  7. if (Z_TYPE_P (arr) == IS_NULL)
  8. {
  9. array_init (arr);
  10. }
  11. else if (Z_TYPE_P (arr) != IS_ARRAY)
  12. {
  13. php_error_docref (NULL TSRMLS_CC, E_WARNING,
  14. "Cannot use a scalar value as an array");
  15. array_init (arr);
  16. }
  17. return Z_ARRVAL_P (arr);
  18. }
  19. /* P_VAR points into a symbol table, at a variable which we wish to index as a hashtable. */
  20. static HashTable *
  21. extract_ht (zval ** p_var TSRMLS_DC)
  22. {
  23. sep_copy_on_write (p_var);
  24. return extract_ht_ex (*p_var TSRMLS_CC);
  25. }
  26. /* Using IND as a key to HT, call the appropriate zend_index_X
  27. * function with data as a parameter, and return its result. This
  28. * updates the zval** pointed to by DATA. */
  29. static int
  30. ht_find (HashTable * ht, zval * ind, zval *** data)
  31. {
  32. int result;
  33. if (Z_TYPE_P (ind) == IS_LONG || Z_TYPE_P (ind) == IS_BOOL)
  34. {
  35. result = zend_hash_index_find (ht, Z_LVAL_P (ind), (void **) data);
  36. }
  37. else if (Z_TYPE_P (ind) == IS_DOUBLE)
  38. {
  39. result = zend_hash_index_find (ht, (long) Z_DVAL_P (ind),
  40. (void **) data);
  41. }
  42. else if (Z_TYPE_P (ind) == IS_NULL)
  43. {
  44. result = zend_hash_find (ht, "", sizeof (""), (void **)data);
  45. }
  46. else if (Z_TYPE_P (ind) == IS_STRING)
  47. {
  48. result = zend_symtable_find (ht, Z_STRVAL_P (ind),
  49. Z_STRLEN_P (ind) + 1, (void **) data);
  50. }
  51. else
  52. {
  53. // TODO: I believe this might need a warning.
  54. // TODO avoid alloc
  55. // use a string index for other types
  56. zval *string_index;
  57. MAKE_STD_ZVAL (string_index);
  58. string_index->value = ind->value;
  59. string_index->type = ind->type;
  60. zval_copy_ctor (string_index);
  61. convert_to_string (string_index);
  62. result = zend_symtable_find (ht, Z_STRVAL_P (string_index),
  63. Z_STRLEN_P (string_index) + 1,
  64. (void **) data);
  65. zval_ptr_dtor (&string_index);
  66. }
  67. return result;
  68. }
  69. static int
  70. check_array_index_type (zval * ind TSRMLS_DC)
  71. {
  72. if (Z_TYPE_P (ind) == IS_OBJECT || Z_TYPE_P (ind) == IS_ARRAY)
  73. {
  74. php_error_docref (NULL TSRMLS_CC, E_WARNING, "Illegal offset type");
  75. return 0;
  76. }
  77. return 1;
  78. }
  79. // Update a hashtable using a zval* index
  80. static void
  81. ht_update (HashTable * ht, zval * ind, zval * val, zval *** dest)
  82. {
  83. int result;
  84. if (Z_TYPE_P (ind) == IS_LONG || Z_TYPE_P (ind) == IS_BOOL)
  85. {
  86. result = zend_hash_index_update (ht, Z_LVAL_P (ind), &val,
  87. sizeof (zval *), (void **) dest);
  88. }
  89. else if (Z_TYPE_P (ind) == IS_DOUBLE)
  90. {
  91. result = zend_hash_index_update (ht, (long) Z_DVAL_P (ind),
  92. &val, sizeof (zval *), (void **) dest);
  93. }
  94. else if (Z_TYPE_P (ind) == IS_NULL)
  95. {
  96. result = zend_hash_update (ht, "", sizeof (""), &val,
  97. sizeof (zval *), (void **) dest);
  98. }
  99. else if (Z_TYPE_P (ind) == IS_STRING)
  100. {
  101. result = zend_symtable_update (ht, Z_STRVAL_P (ind),
  102. Z_STRLEN_P (ind) + 1,
  103. &val, sizeof (zval *), (void **) dest);
  104. }
  105. else
  106. {
  107. // TODO avoid alloc
  108. zval *string_index;
  109. MAKE_STD_ZVAL (string_index);
  110. string_index->value = ind->value;
  111. string_index->type = ind->type;
  112. zval_copy_ctor (string_index);
  113. convert_to_string (string_index);
  114. result = zend_symtable_update (ht, Z_STRVAL_P (string_index),
  115. Z_STRLEN_P (string_index) + 1,
  116. &val, sizeof (zval *), (void **) dest);
  117. zval_ptr_dtor (&string_index);
  118. }
  119. assert (result == SUCCESS);
  120. }
  121. // Delete from a hashtable using a zval* index
  122. static void
  123. ht_delete (HashTable * ht, zval * ind)
  124. {
  125. // This may fail if the index doesnt exist, which is fine.
  126. if (Z_TYPE_P (ind) == IS_LONG || Z_TYPE_P (ind) == IS_BOOL)
  127. {
  128. zend_hash_index_del (ht, Z_LVAL_P (ind));
  129. }
  130. else if (Z_TYPE_P (ind) == IS_DOUBLE)
  131. {
  132. zend_hash_index_del (ht, (long) Z_DVAL_P (ind));
  133. }
  134. else if (Z_TYPE_P (ind) == IS_NULL)
  135. {
  136. zend_hash_del (ht, "", sizeof (""));
  137. }
  138. else if (Z_TYPE_P (ind) == IS_STRING)
  139. {
  140. zend_hash_del (ht, Z_STRVAL_P (ind), Z_STRLEN_P (ind) + 1);
  141. }
  142. else
  143. {
  144. // TODO avoid alloc
  145. zval *string_index;
  146. MAKE_STD_ZVAL (string_index);
  147. string_index->value = ind->value;
  148. string_index->type = ind->type;
  149. zval_copy_ctor (string_index);
  150. convert_to_string (string_index);
  151. zend_hash_del (ht, Z_STRVAL_P (string_index),
  152. Z_STRLEN_P (string_index) + 1);
  153. zval_ptr_dtor (&string_index);
  154. }
  155. }
  156. // Check if a key exists in a hashtable
  157. static int
  158. ht_exists (HashTable * ht, zval * ind)
  159. {
  160. if (Z_TYPE_P (ind) == IS_LONG || Z_TYPE_P (ind) == IS_BOOL)
  161. {
  162. return zend_hash_index_exists (ht, Z_LVAL_P (ind));
  163. }
  164. else if (Z_TYPE_P (ind) == IS_DOUBLE)
  165. {
  166. return zend_hash_index_exists (ht, (long) Z_DVAL_P (ind));
  167. }
  168. else if (Z_TYPE_P (ind) == IS_NULL)
  169. {
  170. return zend_hash_exists (ht, "", sizeof (""));
  171. }
  172. else if (Z_TYPE_P (ind) == IS_STRING)
  173. {
  174. return zend_hash_exists (ht, Z_STRVAL_P (ind), Z_STRLEN_P (ind) + 1);
  175. }
  176. else
  177. {
  178. // TODO avoid alloc
  179. int result;
  180. zval *string_index;
  181. MAKE_STD_ZVAL (string_index);
  182. string_index->value = ind->value;
  183. string_index->type = ind->type;
  184. zval_copy_ctor (string_index);
  185. convert_to_string (string_index);
  186. result = zend_hash_exists (ht, Z_STRVAL_P (string_index),
  187. Z_STRLEN_P (string_index) + 1);
  188. zval_ptr_dtor (&string_index);
  189. return result;
  190. }
  191. assert (0);
  192. }
  193. static zval **
  194. get_ht_entry (zval ** p_var, zval * ind TSRMLS_DC)
  195. {
  196. if (Z_TYPE_P (*p_var) == IS_STRING)
  197. {
  198. if (Z_STRLEN_PP (p_var) > 0)
  199. {
  200. php_error_docref (NULL TSRMLS_CC, E_ERROR,
  201. "Cannot create references to/from string offsets nor overloaded objects");
  202. }
  203. }
  204. if (Z_TYPE_P (*p_var) != IS_ARRAY)
  205. {
  206. zval_ptr_dtor (p_var);
  207. ALLOC_INIT_ZVAL (*p_var);
  208. array_init (*p_var);
  209. }
  210. HashTable *ht = extract_ht (p_var TSRMLS_CC);
  211. zval **data;
  212. if (ht_find (ht, ind, &data) == SUCCESS)
  213. {
  214. assert (data != NULL);
  215. return data;
  216. }
  217. // If we dont find it, put EG (uninitialized_zval_ptr) into the
  218. // hashtable, and return a pointer to its container.
  219. Z_ADDREF_P(EG(uninitialized_zval_ptr));
  220. ht_update (ht, ind, EG (uninitialized_zval_ptr), &data);
  221. assert (data != NULL);
  222. return data;
  223. }
  224. // Like extract_ht_ex, but for objects
  225. static HashTable *
  226. extract_field_ex (zval * obj TSRMLS_DC)
  227. {
  228. // TODO: this likely should be inlined somewhere.
  229. assert (!in_copy_on_write (obj));
  230. if (Z_TYPE_P (obj) == IS_NULL)
  231. {
  232. assert (0);
  233. // TODO: implement initialization
  234. }
  235. else if (Z_TYPE_P (obj) != IS_OBJECT)
  236. {
  237. // TODO: test if this is the right error message
  238. php_error_docref (NULL TSRMLS_CC, E_WARNING,
  239. "Cannot use a scalar value as an object");
  240. // TODO: implement initialization
  241. assert (0);
  242. }
  243. return Z_OBJPROP_P (obj);
  244. }
  245. // Like extract_ht, but for objects
  246. static HashTable *
  247. extract_field (zval ** p_var TSRMLS_DC)
  248. {
  249. sep_copy_on_write (p_var);
  250. return extract_field_ex (*p_var TSRMLS_CC);
  251. }
  252. // Like get_ht_entry, but for objects
  253. static zval **
  254. get_field (zval ** p_var, char *ind TSRMLS_DC)
  255. {
  256. if (Z_TYPE_P (*p_var) != IS_OBJECT)
  257. {
  258. // TODO: implement initialization
  259. assert (0);
  260. }
  261. HashTable *ht = extract_field (p_var TSRMLS_CC);
  262. zval **data;
  263. if (zend_symtable_find (ht, ind, strlen (ind) + 1, (void **) &data) ==
  264. SUCCESS)
  265. {
  266. assert (data != NULL);
  267. return data;
  268. }
  269. // If we dont find it, put EG (uninitialized_zval_ptr) into the
  270. // hashtable, and return a pointer to its container.
  271. Z_ADDREF_P(EG(uninitialized_zval_ptr));
  272. zend_symtable_update (ht, ind, strlen (ind) + 1,
  273. &EG (uninitialized_zval_ptr), sizeof (zval *),
  274. (void **) &data);
  275. assert (data != NULL);
  276. return data;
  277. }
  278. void
  279. read_array (zval ** result, zval * array, zval * ind TSRMLS_DC)
  280. {
  281. // Memory can be allocated in read_string_index
  282. if (array == EG (uninitialized_zval_ptr))
  283. {
  284. *result = array;
  285. return;
  286. }
  287. // Since we know its an array, and we dont write to it, we dont need
  288. // to separate it.
  289. HashTable *ht = Z_ARRVAL_P (array);
  290. // find the result
  291. zval **p_result;
  292. if (ht_find (ht, ind, &p_result) == SUCCESS)
  293. {
  294. *result = *p_result;
  295. return;
  296. }
  297. *result = EG (uninitialized_zval_ptr);
  298. }
  299. /* If its not an array, convert it into an array. */
  300. static void
  301. check_array_type (zval ** p_var TSRMLS_DC)
  302. {
  303. if ((Z_TYPE_P (*p_var) == IS_BOOL && !Z_BVAL_PP (p_var))
  304. || Z_TYPE_P (*p_var) == IS_NULL
  305. || (Z_TYPE_P (*p_var) == IS_STRING && Z_STRLEN_PP (p_var) == 0))
  306. {
  307. // Non ref use new values
  308. if (!PZVAL_IS_REF (*p_var))
  309. {
  310. zval_ptr_dtor (p_var);
  311. ALLOC_INIT_ZVAL (*p_var);
  312. }
  313. else
  314. // Refs are just replaced
  315. zval_dtor (*p_var);
  316. array_init (*p_var);
  317. }
  318. else if (Z_TYPE_PP (p_var) != IS_STRING && Z_TYPE_PP (p_var) != IS_ARRAY)
  319. {
  320. // TODO: why are these different types than pushing
  321. php_error_docref (NULL TSRMLS_CC, E_WARNING,
  322. "Cannot use a scalar value as an array");
  323. }
  324. }
  325. /* If its not an array, convert it into an object. */
  326. static void
  327. check_object_type (zval ** p_var TSRMLS_DC)
  328. {
  329. // TODO: implement
  330. }
  331. /* Push EG (uninitialized_zval_ptr) and return a pointer into the ht
  332. * for it */
  333. /*
  334. * Converted to array automatically:
  335. * ""
  336. * NULL
  337. * false
  338. *
  339. * Warning, no conversion:
  340. * ints
  341. * floats
  342. * true
  343. *
  344. * Error, no conversion:
  345. * strings other than ""
  346. */
  347. // TODO: objects, resources, etc
  348. static zval **
  349. push_and_index_ht (zval ** p_var TSRMLS_DC)
  350. {
  351. // Check for errors conditions
  352. if (Z_TYPE_P (*p_var) == IS_STRING && Z_STRLEN_PP (p_var) > 0)
  353. {
  354. php_error_docref (NULL TSRMLS_CC, E_ERROR,
  355. "[] operator not supported for strings");
  356. assert (0); // unreachable
  357. }
  358. if (Z_TYPE_P (*p_var) == IS_BOOL && Z_BVAL_PP (p_var)
  359. || Z_TYPE_P (*p_var) == IS_LONG || Z_TYPE_P (*p_var) == IS_DOUBLE)
  360. {
  361. php_error_docref (NULL TSRMLS_CC, E_WARNING,
  362. "Cannot use a scalar value as an array");
  363. return NULL;
  364. }
  365. if (Z_TYPE_P (*p_var) != IS_ARRAY)
  366. {
  367. zval_ptr_dtor (p_var);
  368. ALLOC_INIT_ZVAL (*p_var);
  369. array_init (*p_var);
  370. }
  371. // if its not an array, make it an array
  372. HashTable *ht = extract_ht (p_var TSRMLS_CC);
  373. zval **data;
  374. Z_ADDREF_P(EG(uninitialized_zval_ptr));
  375. int result = zend_hash_next_index_insert (ht, &EG (uninitialized_zval_ptr),
  376. sizeof (zval *), (void **) &data);
  377. assert (result == SUCCESS);
  378. assert (data);
  379. return data;
  380. }