optimize_temp_vars_5.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. #if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
  2. /* ops that use CLs:
  3. op1:
  4. ZEND_FETCH_CONSTANT:
  5. ZEND_INIT_CTOR_CALL:
  6. ZEND_INIT_STATIC_METHOD_CALL:
  7. ZEND_INIT_METHOD_CALL:
  8. ZEND_IMPORT_CLASS:
  9. ZEND_IMPORT_FUNCTION:
  10. ZEND_IMPORT_CONST:
  11. ZEND_ADD_INTERFACE:
  12. ZEND_VERIFY_ABSTRACT_CLASS:
  13. ZEND_NEW:
  14. ZEND_CATCH:
  15. ZEND_INIT_FCALL_BY_NAME:
  16. op2:
  17. ZEND_UNSET_VAR:
  18. ZEND_ISSET_ISEMPTY_VAR:
  19. ZEND_FETCH_UNSET:
  20. ZEND_FETCH_IS:
  21. ZEND_FETCH_R:
  22. ZEND_FETCH_W:
  23. ZEND_FETCH_RW:
  24. ZEND_FETCH_FUNC_ARG:
  25. ZEND_ADD_INTERFACE:
  26. ZEND_INSTANCEOF:
  27. extended_value:
  28. ZEND_DECLARE_INHERITED_CLASS:
  29. ignore result
  30. INIT_METHOD_CALL:
  31. */
  32. #define OP1_CONST_IS_CLASS 1
  33. #define OP2_CONST_IS_CLASS 2
  34. #define EXT_CONST_IS_CLASS 4
  35. #define RESULT_IS_UNUSED 8
  36. static const char op_const_means_class[256] = {
  37. /* 0 */
  38. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  39. /* 32 */
  40. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
  41. /* 64 */
  42. 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 2, 0, 0, 2, 0, 0, 2, 0, 0, 2, 0, 0, 2, 0, 0, 2,
  43. /* 96 */
  44. 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 9, 1, 2, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  45. /* 128 */
  46. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 4, 0, 0, 0, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  47. /* 160 */
  48. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  49. /* 192 */
  50. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  51. /* 224 */
  52. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
  53. };
  54. #endif
  55. #define GET_AVAILABLE_T() \
  56. for (i = 0; i < T; i++) { \
  57. if (!taken_T[i]) { \
  58. break; \
  59. } \
  60. } \
  61. taken_T[i] = 1; \
  62. if (i > max) { \
  63. max = i; \
  64. }
  65. static void optimize_temporary_variables(zend_op_array *op_array)
  66. {
  67. int T = op_array->T;
  68. char *taken_T; /* T index in use */
  69. zend_op **start_of_T; /* opline where T is first used */
  70. char *valid_T; /* Is the map_T valid */
  71. int *map_T; /* Map's the T to its new index */
  72. zend_op *opline, *end;
  73. int currT;
  74. int i;
  75. int max = -1;
  76. int var_to_free = -1;
  77. taken_T = (char *) emalloc(T);
  78. start_of_T = (zend_op **) emalloc(T * sizeof(zend_op *));
  79. valid_T = (char *) emalloc(T);
  80. map_T = (int *) emalloc(T * sizeof(int));
  81. end = op_array->opcodes;
  82. opline = &op_array->opcodes[op_array->last - 1];
  83. /* Find T definition points */
  84. while (opline >= end) {
  85. #if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
  86. if (ZEND_RESULT_TYPE(opline) & (IS_VAR | IS_TMP_VAR | IS_CONST)) {
  87. if (!(op_const_means_class[opline->opcode] & RESULT_IS_UNUSED)) {
  88. start_of_T[VAR_NUM(ZEND_RESULT(opline).var)] = opline;
  89. }
  90. }
  91. #else
  92. if (ZEND_RESULT_TYPE(opline) & (IS_VAR | IS_TMP_VAR)) {
  93. start_of_T[VAR_NUM(ZEND_RESULT(opline).var)] = opline;
  94. }
  95. #endif
  96. opline--;
  97. }
  98. memset(valid_T, 0, T);
  99. memset(taken_T, 0, T);
  100. end = op_array->opcodes;
  101. opline = &op_array->opcodes[op_array->last - 1];
  102. while (opline >= end) {
  103. if ((ZEND_OP1_TYPE(opline) & (IS_VAR | IS_TMP_VAR))
  104. #if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
  105. || ((op_const_means_class[opline->opcode] & OP1_CONST_IS_CLASS) && ZEND_OP1_TYPE(opline) == IS_CONST)
  106. #endif
  107. ) {
  108. currT = VAR_NUM(ZEND_OP1(opline).var);
  109. if (!valid_T[currT]) {
  110. GET_AVAILABLE_T();
  111. map_T[currT] = i;
  112. valid_T[currT] = 1;
  113. }
  114. ZEND_OP1(opline).var = NUM_VAR(map_T[currT]);
  115. }
  116. /* Skip OP_DATA */
  117. if (opline->opcode == ZEND_OP_DATA &&
  118. (opline-1)->opcode == ZEND_ASSIGN_DIM) {
  119. opline--;
  120. continue;
  121. }
  122. if ((ZEND_OP2_TYPE(opline) & (IS_VAR | IS_TMP_VAR))
  123. #if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
  124. || ((op_const_means_class[opline->opcode] & OP2_CONST_IS_CLASS) && ZEND_OP2_TYPE(opline) == IS_CONST)
  125. #endif
  126. ) {
  127. currT = VAR_NUM(ZEND_OP2(opline).var);
  128. if (!valid_T[currT]) {
  129. GET_AVAILABLE_T();
  130. map_T[currT] = i;
  131. valid_T[currT] = 1;
  132. }
  133. ZEND_OP2(opline).var = NUM_VAR(map_T[currT]);
  134. }
  135. #if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
  136. if ((op_const_means_class[opline->opcode] & EXT_CONST_IS_CLASS)) {
  137. #else
  138. if (opline->opcode == ZEND_DECLARE_INHERITED_CLASS ||
  139. opline->opcode == ZEND_DECLARE_INHERITED_CLASS_DELAYED) {
  140. #endif
  141. currT = VAR_NUM(opline->extended_value);
  142. if (!valid_T[currT]) {
  143. GET_AVAILABLE_T();
  144. map_T[currT] = i;
  145. valid_T[currT] = 1;
  146. }
  147. opline->extended_value = NUM_VAR(map_T[currT]);
  148. }
  149. /* Allocate OP_DATA->op2 after "operands", but before "result" */
  150. if (opline->opcode == ZEND_ASSIGN_DIM &&
  151. (opline + 1)->opcode == ZEND_OP_DATA &&
  152. ZEND_OP2_TYPE(opline + 1) & (IS_VAR | IS_TMP_VAR)) {
  153. currT = VAR_NUM(ZEND_OP2(opline + 1).var);
  154. GET_AVAILABLE_T();
  155. map_T[currT] = i;
  156. valid_T[currT] = 1;
  157. taken_T[i] = 0;
  158. ZEND_OP2(opline + 1).var = NUM_VAR(i);
  159. var_to_free = i;
  160. }
  161. #if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
  162. if (ZEND_RESULT_TYPE(opline) & (IS_VAR | IS_TMP_VAR | IS_CONST)) {
  163. if (!(op_const_means_class[opline->opcode] & RESULT_IS_UNUSED)) {
  164. #else
  165. if (ZEND_RESULT_TYPE(opline) & (IS_VAR | IS_TMP_VAR)) {
  166. #endif
  167. currT = VAR_NUM(ZEND_RESULT(opline).var);
  168. if (valid_T[currT]) {
  169. if (start_of_T[currT] == opline) {
  170. taken_T[map_T[currT]] = 0;
  171. }
  172. ZEND_RESULT(opline).var = NUM_VAR(map_T[currT]);
  173. } else { /* Au still needs to be assigned a T which is a bit dumb. Should consider changing Zend */
  174. GET_AVAILABLE_T();
  175. if (RESULT_UNUSED(opline)) {
  176. taken_T[i] = 0;
  177. } else {
  178. /* Code which gets here is using a wrongly built opcode such as RECV() */
  179. map_T[currT] = i;
  180. valid_T[currT] = 1;
  181. }
  182. ZEND_RESULT(opline).var = NUM_VAR(i);
  183. }
  184. #if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
  185. }
  186. #endif
  187. }
  188. if (var_to_free >= 0) {
  189. taken_T[var_to_free] = 0;
  190. var_to_free = -1;
  191. }
  192. opline--;
  193. }
  194. efree(taken_T);
  195. efree(start_of_T);
  196. efree(valid_T);
  197. efree(map_T);
  198. op_array->T = max + 1;
  199. }