zend_optimizer.c 52 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671
  1. /*
  2. +----------------------------------------------------------------------+
  3. | Zend OPcache |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1998-2018 The PHP Group |
  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. | Authors: Andi Gutmans <andi@php.net> |
  16. | Zeev Suraski <zeev@php.net> |
  17. | Stanislav Malyshev <stas@zend.com> |
  18. | Dmitry Stogov <dmitry@php.net> |
  19. +----------------------------------------------------------------------+
  20. */
  21. #include "php.h"
  22. #include "Optimizer/zend_optimizer.h"
  23. #include "Optimizer/zend_optimizer_internal.h"
  24. #include "zend_API.h"
  25. #include "zend_constants.h"
  26. #include "zend_execute.h"
  27. #include "zend_vm.h"
  28. #include "zend_cfg.h"
  29. #include "zend_func_info.h"
  30. #include "zend_call_graph.h"
  31. #include "zend_inference.h"
  32. #include "zend_dump.h"
  33. #ifndef HAVE_DFA_PASS
  34. # define HAVE_DFA_PASS 1
  35. #endif
  36. static void zend_optimizer_zval_dtor_wrapper(zval *zvalue)
  37. {
  38. zval_ptr_dtor_nogc(zvalue);
  39. }
  40. void zend_optimizer_collect_constant(zend_optimizer_ctx *ctx, zval *name, zval* value)
  41. {
  42. zval val;
  43. if (!ctx->constants) {
  44. ctx->constants = zend_arena_alloc(&ctx->arena, sizeof(HashTable));
  45. zend_hash_init(ctx->constants, 16, NULL, zend_optimizer_zval_dtor_wrapper, 0);
  46. }
  47. ZVAL_COPY(&val, value);
  48. zend_hash_add(ctx->constants, Z_STR_P(name), &val);
  49. }
  50. zend_uchar zend_compound_assign_to_binary_op(zend_uchar opcode)
  51. {
  52. switch (opcode) {
  53. case ZEND_ASSIGN_ADD: return ZEND_ADD;
  54. case ZEND_ASSIGN_SUB: return ZEND_SUB;
  55. case ZEND_ASSIGN_MUL: return ZEND_MUL;
  56. case ZEND_ASSIGN_DIV: return ZEND_DIV;
  57. case ZEND_ASSIGN_MOD: return ZEND_MOD;
  58. case ZEND_ASSIGN_SL: return ZEND_SL;
  59. case ZEND_ASSIGN_SR: return ZEND_SR;
  60. case ZEND_ASSIGN_CONCAT: return ZEND_CONCAT;
  61. case ZEND_ASSIGN_BW_OR: return ZEND_BW_OR;
  62. case ZEND_ASSIGN_BW_AND: return ZEND_BW_AND;
  63. case ZEND_ASSIGN_BW_XOR: return ZEND_BW_XOR;
  64. case ZEND_ASSIGN_POW: return ZEND_POW;
  65. EMPTY_SWITCH_DEFAULT_CASE()
  66. }
  67. }
  68. int zend_optimizer_eval_binary_op(zval *result, zend_uchar opcode, zval *op1, zval *op2) /* {{{ */
  69. {
  70. binary_op_type binary_op = get_binary_op(opcode);
  71. int er, ret;
  72. if (zend_binary_op_produces_numeric_string_error(opcode, op1, op2)) {
  73. /* produces numeric string E_NOTICE/E_WARNING */
  74. return FAILURE;
  75. }
  76. switch (opcode) {
  77. case ZEND_ADD:
  78. if ((Z_TYPE_P(op1) == IS_ARRAY
  79. || Z_TYPE_P(op2) == IS_ARRAY)
  80. && Z_TYPE_P(op1) != Z_TYPE_P(op2)) {
  81. /* produces "Unsupported operand types" exception */
  82. return FAILURE;
  83. }
  84. break;
  85. case ZEND_DIV:
  86. case ZEND_MOD:
  87. if (zval_get_long(op2) == 0) {
  88. /* division by 0 */
  89. return FAILURE;
  90. }
  91. /* break missing intentionally */
  92. case ZEND_SUB:
  93. case ZEND_MUL:
  94. case ZEND_POW:
  95. case ZEND_CONCAT:
  96. case ZEND_FAST_CONCAT:
  97. if (Z_TYPE_P(op1) == IS_ARRAY
  98. || Z_TYPE_P(op2) == IS_ARRAY) {
  99. /* produces "Unsupported operand types" exception */
  100. return FAILURE;
  101. }
  102. break;
  103. case ZEND_SL:
  104. case ZEND_SR:
  105. if (zval_get_long(op2) < 0) {
  106. /* shift by negative number */
  107. return FAILURE;
  108. }
  109. break;
  110. }
  111. er = EG(error_reporting);
  112. EG(error_reporting) = 0;
  113. ret = binary_op(result, op1, op2);
  114. EG(error_reporting) = er;
  115. return ret;
  116. }
  117. /* }}} */
  118. int zend_optimizer_eval_unary_op(zval *result, zend_uchar opcode, zval *op1) /* {{{ */
  119. {
  120. unary_op_type unary_op = get_unary_op(opcode);
  121. if (unary_op) {
  122. if (opcode == ZEND_BW_NOT
  123. && Z_TYPE_P(op1) != IS_LONG
  124. && Z_TYPE_P(op1) != IS_DOUBLE
  125. && Z_TYPE_P(op1) != IS_STRING) {
  126. /* produces "Unsupported operand types" exception */
  127. return FAILURE;
  128. }
  129. return unary_op(result, op1);
  130. } else { /* ZEND_BOOL */
  131. ZVAL_BOOL(result, zend_is_true(op1));
  132. return SUCCESS;
  133. }
  134. }
  135. /* }}} */
  136. int zend_optimizer_eval_cast(zval *result, uint32_t type, zval *op1) /* {{{ */
  137. {
  138. switch (type) {
  139. case IS_NULL:
  140. ZVAL_NULL(result);
  141. return SUCCESS;
  142. case _IS_BOOL:
  143. ZVAL_BOOL(result, zval_is_true(op1));
  144. return SUCCESS;
  145. case IS_LONG:
  146. ZVAL_LONG(result, zval_get_long(op1));
  147. return SUCCESS;
  148. case IS_DOUBLE:
  149. ZVAL_DOUBLE(result, zval_get_double(op1));
  150. return SUCCESS;
  151. case IS_STRING:
  152. /* Conversion from double to string takes into account run-time
  153. 'precision' setting and cannot be evaluated at compile-time */
  154. if (Z_TYPE_P(op1) != IS_ARRAY && Z_TYPE_P(op1) != IS_DOUBLE) {
  155. ZVAL_STR(result, zval_get_string(op1));
  156. return SUCCESS;
  157. }
  158. break;
  159. case IS_ARRAY:
  160. ZVAL_COPY(result, op1);
  161. convert_to_array(result);
  162. return SUCCESS;
  163. }
  164. return FAILURE;
  165. }
  166. /* }}} */
  167. int zend_optimizer_eval_strlen(zval *result, zval *op1) /* {{{ */
  168. {
  169. if (Z_TYPE_P(op1) != IS_STRING) {
  170. return FAILURE;
  171. }
  172. ZVAL_LONG(result, Z_STRLEN_P(op1));
  173. return SUCCESS;
  174. }
  175. /* }}} */
  176. int zend_optimizer_get_collected_constant(HashTable *constants, zval *name, zval* value)
  177. {
  178. zval *val;
  179. if ((val = zend_hash_find(constants, Z_STR_P(name))) != NULL) {
  180. ZVAL_COPY(value, val);
  181. return 1;
  182. }
  183. return 0;
  184. }
  185. int zend_optimizer_add_literal(zend_op_array *op_array, zval *zv)
  186. {
  187. int i = op_array->last_literal;
  188. op_array->last_literal++;
  189. op_array->literals = (zval*)erealloc(op_array->literals, op_array->last_literal * sizeof(zval));
  190. ZVAL_COPY_VALUE(&op_array->literals[i], zv);
  191. Z_EXTRA(op_array->literals[i]) = 0;
  192. return i;
  193. }
  194. static inline int zend_optimizer_add_literal_string(zend_op_array *op_array, zend_string *str) {
  195. zval zv;
  196. ZVAL_STR(&zv, str);
  197. zend_string_hash_val(str);
  198. return zend_optimizer_add_literal(op_array, &zv);
  199. }
  200. int zend_optimizer_is_disabled_func(const char *name, size_t len) {
  201. zend_function *fbc = (zend_function *)zend_hash_str_find_ptr(EG(function_table), name, len);
  202. return (fbc && fbc->type == ZEND_INTERNAL_FUNCTION &&
  203. fbc->internal_function.handler == ZEND_FN(display_disabled_function));
  204. }
  205. static inline void drop_leading_backslash(zval *val) {
  206. if (Z_STRVAL_P(val)[0] == '\\') {
  207. zend_string *str = zend_string_init(Z_STRVAL_P(val) + 1, Z_STRLEN_P(val) - 1, 0);
  208. zval_ptr_dtor_nogc(val);
  209. ZVAL_STR(val, str);
  210. }
  211. }
  212. static inline uint32_t alloc_cache_slots(zend_op_array *op_array, uint32_t num) {
  213. uint32_t ret = op_array->cache_size;
  214. op_array->cache_size += num * sizeof(void *);
  215. return ret;
  216. }
  217. #define REQUIRES_STRING(val) do { \
  218. if (Z_TYPE_P(val) != IS_STRING) { \
  219. return 0; \
  220. } \
  221. } while (0)
  222. #define TO_STRING_NOWARN(val) do { \
  223. if (Z_TYPE_P(val) >= IS_ARRAY) { \
  224. return 0; \
  225. } \
  226. convert_to_string(val); \
  227. } while (0)
  228. int zend_optimizer_update_op1_const(zend_op_array *op_array,
  229. zend_op *opline,
  230. zval *val)
  231. {
  232. switch (opline->opcode) {
  233. case ZEND_FREE:
  234. case ZEND_CHECK_VAR:
  235. MAKE_NOP(opline);
  236. zval_ptr_dtor_nogc(val);
  237. return 1;
  238. case ZEND_SEND_VAR_EX:
  239. case ZEND_SEND_FUNC_ARG:
  240. case ZEND_FETCH_DIM_W:
  241. case ZEND_FETCH_DIM_RW:
  242. case ZEND_FETCH_DIM_FUNC_ARG:
  243. case ZEND_FETCH_DIM_UNSET:
  244. case ZEND_FETCH_LIST_W:
  245. case ZEND_ASSIGN_DIM:
  246. case ZEND_RETURN_BY_REF:
  247. case ZEND_INSTANCEOF:
  248. case ZEND_MAKE_REF:
  249. return 0;
  250. case ZEND_CATCH:
  251. REQUIRES_STRING(val);
  252. drop_leading_backslash(val);
  253. opline->op1.constant = zend_optimizer_add_literal(op_array, val);
  254. opline->extended_value = alloc_cache_slots(op_array, 1) | (opline->extended_value & ZEND_LAST_CATCH);
  255. zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val)));
  256. break;
  257. case ZEND_DEFINED:
  258. REQUIRES_STRING(val);
  259. drop_leading_backslash(val);
  260. opline->op1.constant = zend_optimizer_add_literal(op_array, val);
  261. opline->extended_value = alloc_cache_slots(op_array, 1);
  262. zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val)));
  263. break;
  264. case ZEND_NEW:
  265. REQUIRES_STRING(val);
  266. drop_leading_backslash(val);
  267. opline->op1.constant = zend_optimizer_add_literal(op_array, val);
  268. opline->op2.num = alloc_cache_slots(op_array, 1);
  269. zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val)));
  270. break;
  271. case ZEND_INIT_STATIC_METHOD_CALL:
  272. REQUIRES_STRING(val);
  273. drop_leading_backslash(val);
  274. opline->op1.constant = zend_optimizer_add_literal(op_array, val);
  275. if (opline->op2_type != IS_CONST) {
  276. opline->result.num = alloc_cache_slots(op_array, 1);
  277. }
  278. zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val)));
  279. break;
  280. case ZEND_FETCH_CLASS_CONSTANT:
  281. REQUIRES_STRING(val);
  282. drop_leading_backslash(val);
  283. opline->op1.constant = zend_optimizer_add_literal(op_array, val);
  284. if (opline->op2_type != IS_CONST) {
  285. opline->extended_value = alloc_cache_slots(op_array, 1);
  286. }
  287. zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val)));
  288. break;
  289. case ZEND_FETCH_STATIC_PROP_R:
  290. case ZEND_FETCH_STATIC_PROP_W:
  291. case ZEND_FETCH_STATIC_PROP_RW:
  292. case ZEND_FETCH_STATIC_PROP_IS:
  293. case ZEND_FETCH_STATIC_PROP_UNSET:
  294. case ZEND_FETCH_STATIC_PROP_FUNC_ARG:
  295. case ZEND_UNSET_STATIC_PROP:
  296. TO_STRING_NOWARN(val);
  297. opline->op1.constant = zend_optimizer_add_literal(op_array, val);
  298. if (opline->op2_type == IS_CONST && opline->extended_value + sizeof(void*) == op_array->cache_size) {
  299. op_array->cache_size += sizeof(void *);
  300. } else {
  301. opline->extended_value = alloc_cache_slots(op_array, 2);
  302. }
  303. break;
  304. case ZEND_ISSET_ISEMPTY_STATIC_PROP:
  305. TO_STRING_NOWARN(val);
  306. opline->op1.constant = zend_optimizer_add_literal(op_array, val);
  307. if (opline->op2_type == IS_CONST && (opline->extended_value & ~ZEND_ISEMPTY) + sizeof(void*) == op_array->cache_size) {
  308. op_array->cache_size += sizeof(void *);
  309. } else {
  310. opline->extended_value = alloc_cache_slots(op_array, 2) | (opline->extended_value & ZEND_ISEMPTY);
  311. }
  312. break;
  313. case ZEND_SEND_VAR:
  314. opline->opcode = ZEND_SEND_VAL;
  315. opline->op1.constant = zend_optimizer_add_literal(op_array, val);
  316. break;
  317. case ZEND_SEPARATE:
  318. case ZEND_SEND_VAR_NO_REF:
  319. case ZEND_SEND_VAR_NO_REF_EX:
  320. return 0;
  321. case ZEND_VERIFY_RETURN_TYPE:
  322. /* This would require a non-local change.
  323. * zend_optimizer_replace_by_const() supports this. */
  324. return 0;
  325. case ZEND_CASE:
  326. case ZEND_FETCH_LIST_R:
  327. return 0;
  328. case ZEND_CONCAT:
  329. case ZEND_FAST_CONCAT:
  330. case ZEND_FETCH_R:
  331. case ZEND_FETCH_W:
  332. case ZEND_FETCH_RW:
  333. case ZEND_FETCH_IS:
  334. case ZEND_FETCH_UNSET:
  335. case ZEND_FETCH_FUNC_ARG:
  336. TO_STRING_NOWARN(val);
  337. if (opline->opcode == ZEND_CONCAT && opline->op2_type == IS_CONST) {
  338. opline->opcode = ZEND_FAST_CONCAT;
  339. }
  340. /* break missing intentionally */
  341. default:
  342. opline->op1.constant = zend_optimizer_add_literal(op_array, val);
  343. break;
  344. }
  345. opline->op1_type = IS_CONST;
  346. if (Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING) {
  347. zend_string_hash_val(Z_STR(ZEND_OP1_LITERAL(opline)));
  348. }
  349. return 1;
  350. }
  351. int zend_optimizer_update_op2_const(zend_op_array *op_array,
  352. zend_op *opline,
  353. zval *val)
  354. {
  355. zval tmp;
  356. switch (opline->opcode) {
  357. case ZEND_ASSIGN_REF:
  358. case ZEND_FAST_CALL:
  359. return 0;
  360. case ZEND_FETCH_CLASS:
  361. if ((opline + 1)->opcode == ZEND_INSTANCEOF &&
  362. (opline + 1)->op2.var == opline->result.var) {
  363. return 0;
  364. }
  365. /* break missing intentionally */
  366. case ZEND_INSTANCEOF:
  367. REQUIRES_STRING(val);
  368. drop_leading_backslash(val);
  369. opline->op2.constant = zend_optimizer_add_literal(op_array, val);
  370. zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val)));
  371. opline->extended_value = alloc_cache_slots(op_array, 1);
  372. break;
  373. case ZEND_ADD_INTERFACE:
  374. case ZEND_ADD_TRAIT:
  375. REQUIRES_STRING(val);
  376. drop_leading_backslash(val);
  377. opline->op2.constant = zend_optimizer_add_literal(op_array, val);
  378. zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val)));
  379. break;
  380. case ZEND_INIT_FCALL_BY_NAME:
  381. REQUIRES_STRING(val);
  382. drop_leading_backslash(val);
  383. opline->op2.constant = zend_optimizer_add_literal(op_array, val);
  384. zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val)));
  385. opline->result.num = alloc_cache_slots(op_array, 1);
  386. break;
  387. case ZEND_FETCH_STATIC_PROP_R:
  388. case ZEND_FETCH_STATIC_PROP_W:
  389. case ZEND_FETCH_STATIC_PROP_RW:
  390. case ZEND_FETCH_STATIC_PROP_IS:
  391. case ZEND_FETCH_STATIC_PROP_UNSET:
  392. case ZEND_FETCH_STATIC_PROP_FUNC_ARG:
  393. case ZEND_UNSET_STATIC_PROP:
  394. REQUIRES_STRING(val);
  395. drop_leading_backslash(val);
  396. opline->op2.constant = zend_optimizer_add_literal(op_array, val);
  397. zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val)));
  398. if (opline->op1_type != IS_CONST) {
  399. opline->extended_value = alloc_cache_slots(op_array, 1);
  400. }
  401. break;
  402. case ZEND_ISSET_ISEMPTY_STATIC_PROP:
  403. REQUIRES_STRING(val);
  404. drop_leading_backslash(val);
  405. opline->op2.constant = zend_optimizer_add_literal(op_array, val);
  406. zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val)));
  407. if (opline->op1_type != IS_CONST) {
  408. opline->extended_value = alloc_cache_slots(op_array, 1) | (opline->extended_value & ZEND_ISEMPTY);
  409. }
  410. break;
  411. case ZEND_INIT_FCALL:
  412. REQUIRES_STRING(val);
  413. if (Z_REFCOUNT_P(val) == 1) {
  414. zend_str_tolower(Z_STRVAL_P(val), Z_STRLEN_P(val));
  415. } else {
  416. ZVAL_STR(&tmp, zend_string_tolower(Z_STR_P(val)));
  417. zval_ptr_dtor_nogc(val);
  418. val = &tmp;
  419. }
  420. opline->op2.constant = zend_optimizer_add_literal(op_array, val);
  421. opline->result.num = alloc_cache_slots(op_array, 1);
  422. break;
  423. case ZEND_INIT_DYNAMIC_CALL:
  424. if (Z_TYPE_P(val) == IS_STRING) {
  425. if (zend_memrchr(Z_STRVAL_P(val), ':', Z_STRLEN_P(val))) {
  426. return 0;
  427. }
  428. if (zend_optimizer_classify_function(Z_STR_P(val), opline->extended_value)) {
  429. /* Dynamic call to various special functions must stay dynamic,
  430. * otherwise would drop a warning */
  431. return 0;
  432. }
  433. opline->opcode = ZEND_INIT_FCALL_BY_NAME;
  434. drop_leading_backslash(val);
  435. opline->op2.constant = zend_optimizer_add_literal(op_array, val);
  436. zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val)));
  437. opline->result.num = alloc_cache_slots(op_array, 1);
  438. } else {
  439. opline->op2.constant = zend_optimizer_add_literal(op_array, val);
  440. }
  441. break;
  442. case ZEND_INIT_METHOD_CALL:
  443. REQUIRES_STRING(val);
  444. opline->op2.constant = zend_optimizer_add_literal(op_array, val);
  445. zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val)));
  446. opline->result.num = alloc_cache_slots(op_array, 2);
  447. break;
  448. case ZEND_INIT_STATIC_METHOD_CALL:
  449. REQUIRES_STRING(val);
  450. opline->op2.constant = zend_optimizer_add_literal(op_array, val);
  451. zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val)));
  452. if (opline->op1_type != IS_CONST) {
  453. opline->result.num = alloc_cache_slots(op_array, 2);
  454. }
  455. break;
  456. case ZEND_ASSIGN_OBJ:
  457. case ZEND_FETCH_OBJ_R:
  458. case ZEND_FETCH_OBJ_W:
  459. case ZEND_FETCH_OBJ_RW:
  460. case ZEND_FETCH_OBJ_IS:
  461. case ZEND_FETCH_OBJ_UNSET:
  462. case ZEND_FETCH_OBJ_FUNC_ARG:
  463. case ZEND_UNSET_OBJ:
  464. case ZEND_PRE_INC_OBJ:
  465. case ZEND_PRE_DEC_OBJ:
  466. case ZEND_POST_INC_OBJ:
  467. case ZEND_POST_DEC_OBJ:
  468. TO_STRING_NOWARN(val);
  469. opline->op2.constant = zend_optimizer_add_literal(op_array, val);
  470. opline->extended_value = alloc_cache_slots(op_array, 2);
  471. break;
  472. case ZEND_ISSET_ISEMPTY_PROP_OBJ:
  473. TO_STRING_NOWARN(val);
  474. opline->op2.constant = zend_optimizer_add_literal(op_array, val);
  475. opline->extended_value = alloc_cache_slots(op_array, 2) | (opline->extended_value & ZEND_ISEMPTY);
  476. break;
  477. case ZEND_ASSIGN_ADD:
  478. case ZEND_ASSIGN_SUB:
  479. case ZEND_ASSIGN_MUL:
  480. case ZEND_ASSIGN_DIV:
  481. case ZEND_ASSIGN_POW:
  482. case ZEND_ASSIGN_MOD:
  483. case ZEND_ASSIGN_SL:
  484. case ZEND_ASSIGN_SR:
  485. case ZEND_ASSIGN_CONCAT:
  486. case ZEND_ASSIGN_BW_OR:
  487. case ZEND_ASSIGN_BW_AND:
  488. case ZEND_ASSIGN_BW_XOR:
  489. if (opline->extended_value == ZEND_ASSIGN_OBJ) {
  490. TO_STRING_NOWARN(val);
  491. opline->op2.constant = zend_optimizer_add_literal(op_array, val);
  492. (opline+1)->extended_value = alloc_cache_slots(op_array, 2);
  493. } else if (opline->extended_value == ZEND_ASSIGN_DIM) {
  494. if (Z_TYPE_P(val) == IS_STRING) {
  495. zend_ulong index;
  496. if (ZEND_HANDLE_NUMERIC(Z_STR_P(val), index)) {
  497. ZVAL_LONG(&tmp, index);
  498. opline->op2.constant = zend_optimizer_add_literal(op_array, &tmp);
  499. zend_string_hash_val(Z_STR_P(val));
  500. zend_optimizer_add_literal(op_array, val);
  501. Z_EXTRA(op_array->literals[opline->op2.constant]) = ZEND_EXTRA_VALUE;
  502. break;
  503. }
  504. }
  505. opline->op2.constant = zend_optimizer_add_literal(op_array, val);
  506. } else {
  507. opline->op2.constant = zend_optimizer_add_literal(op_array, val);
  508. }
  509. break;
  510. case ZEND_ISSET_ISEMPTY_DIM_OBJ:
  511. case ZEND_ASSIGN_DIM:
  512. case ZEND_UNSET_DIM:
  513. case ZEND_FETCH_DIM_R:
  514. case ZEND_FETCH_DIM_W:
  515. case ZEND_FETCH_DIM_RW:
  516. case ZEND_FETCH_DIM_IS:
  517. case ZEND_FETCH_DIM_FUNC_ARG:
  518. case ZEND_FETCH_DIM_UNSET:
  519. case ZEND_FETCH_LIST_R:
  520. case ZEND_FETCH_LIST_W:
  521. if (Z_TYPE_P(val) == IS_STRING) {
  522. zend_ulong index;
  523. if (ZEND_HANDLE_NUMERIC(Z_STR_P(val), index)) {
  524. ZVAL_LONG(&tmp, index);
  525. opline->op2.constant = zend_optimizer_add_literal(op_array, &tmp);
  526. zend_string_hash_val(Z_STR_P(val));
  527. zend_optimizer_add_literal(op_array, val);
  528. Z_EXTRA(op_array->literals[opline->op2.constant]) = ZEND_EXTRA_VALUE;
  529. break;
  530. }
  531. }
  532. opline->op2.constant = zend_optimizer_add_literal(op_array, val);
  533. break;
  534. case ZEND_ADD_ARRAY_ELEMENT:
  535. case ZEND_INIT_ARRAY:
  536. if (Z_TYPE_P(val) == IS_STRING) {
  537. zend_ulong index;
  538. if (ZEND_HANDLE_NUMERIC(Z_STR_P(val), index)) {
  539. zval_ptr_dtor_nogc(val);
  540. ZVAL_LONG(val, index);
  541. }
  542. }
  543. opline->op2.constant = zend_optimizer_add_literal(op_array, val);
  544. break;
  545. case ZEND_ROPE_INIT:
  546. case ZEND_ROPE_ADD:
  547. case ZEND_ROPE_END:
  548. case ZEND_CONCAT:
  549. case ZEND_FAST_CONCAT:
  550. TO_STRING_NOWARN(val);
  551. if (opline->opcode == ZEND_CONCAT && opline->op1_type == IS_CONST) {
  552. opline->opcode = ZEND_FAST_CONCAT;
  553. }
  554. /* break missing intentionally */
  555. default:
  556. opline->op2.constant = zend_optimizer_add_literal(op_array, val);
  557. break;
  558. }
  559. opline->op2_type = IS_CONST;
  560. if (Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING) {
  561. zend_string_hash_val(Z_STR(ZEND_OP2_LITERAL(opline)));
  562. }
  563. return 1;
  564. }
  565. void zend_optimizer_remove_live_range(zend_op_array *op_array, uint32_t var)
  566. {
  567. if (op_array->last_live_range) {
  568. int i = 0;
  569. int j = 0;
  570. do {
  571. if ((op_array->live_range[i].var & ~ZEND_LIVE_MASK) != var) {
  572. if (i != j) {
  573. op_array->live_range[j] = op_array->live_range[i];
  574. }
  575. j++;
  576. }
  577. i++;
  578. } while (i < op_array->last_live_range);
  579. if (i != j) {
  580. op_array->last_live_range = j;
  581. if (j == 0) {
  582. efree(op_array->live_range);
  583. op_array->live_range = NULL;
  584. }
  585. }
  586. }
  587. }
  588. static uint32_t zend_determine_constructor_call(zend_op_array *op_array, uint32_t start) {
  589. int call = 0;
  590. while (++start < op_array->last) {
  591. switch (op_array->opcodes[start].opcode) {
  592. case ZEND_INIT_FCALL_BY_NAME:
  593. case ZEND_INIT_NS_FCALL_BY_NAME:
  594. case ZEND_INIT_STATIC_METHOD_CALL:
  595. case ZEND_INIT_METHOD_CALL:
  596. case ZEND_INIT_FCALL:
  597. case ZEND_NEW:
  598. case ZEND_INIT_DYNAMIC_CALL:
  599. case ZEND_INIT_USER_CALL:
  600. call++;
  601. break;
  602. case ZEND_DO_FCALL:
  603. if (call == 0) {
  604. return start;
  605. }
  606. /* break missing intentionally */
  607. case ZEND_DO_ICALL:
  608. case ZEND_DO_UCALL:
  609. case ZEND_DO_FCALL_BY_NAME:
  610. call--;
  611. break;
  612. default:
  613. break;
  614. }
  615. }
  616. ZEND_ASSERT(0);
  617. return -1;
  618. }
  619. void zend_optimizer_remove_live_range_ex(zend_op_array *op_array, uint32_t var, uint32_t start)
  620. {
  621. uint32_t i = 0;
  622. switch (op_array->opcodes[start].opcode) {
  623. case ZEND_ROPE_ADD:
  624. case ZEND_ADD_ARRAY_ELEMENT:
  625. return;
  626. case ZEND_ROPE_INIT:
  627. var |= ZEND_LIVE_ROPE;
  628. break;
  629. case ZEND_BEGIN_SILENCE:
  630. var |= ZEND_LIVE_SILENCE;
  631. break;
  632. case ZEND_FE_RESET_R:
  633. case ZEND_FE_RESET_RW:
  634. var |= ZEND_LIVE_LOOP;
  635. start++;
  636. break;
  637. case ZEND_NEW:
  638. start = zend_determine_constructor_call(op_array, start);
  639. start++;
  640. break;
  641. default:
  642. start++;
  643. }
  644. while (i < op_array->last_live_range) {
  645. if (op_array->live_range[i].var == var
  646. && op_array->live_range[i].start == start) {
  647. op_array->last_live_range--;
  648. if (i < op_array->last_live_range) {
  649. memmove(&op_array->live_range[i], &op_array->live_range[i+1], (op_array->last_live_range - i) * sizeof(zend_live_range));
  650. }
  651. break;
  652. }
  653. i++;
  654. }
  655. }
  656. int zend_optimizer_replace_by_const(zend_op_array *op_array,
  657. zend_op *opline,
  658. zend_uchar type,
  659. uint32_t var,
  660. zval *val)
  661. {
  662. zend_op *end = op_array->opcodes + op_array->last;
  663. while (opline < end) {
  664. if (opline->op1_type == type &&
  665. opline->op1.var == var) {
  666. switch (opline->opcode) {
  667. case ZEND_FETCH_DIM_W:
  668. case ZEND_FETCH_DIM_RW:
  669. case ZEND_FETCH_DIM_FUNC_ARG:
  670. case ZEND_FETCH_DIM_UNSET:
  671. case ZEND_FETCH_LIST_W:
  672. case ZEND_ASSIGN_DIM:
  673. case ZEND_SEPARATE:
  674. case ZEND_RETURN_BY_REF:
  675. return 0;
  676. case ZEND_SEND_VAR:
  677. opline->extended_value = 0;
  678. opline->opcode = ZEND_SEND_VAL;
  679. break;
  680. case ZEND_SEND_VAR_EX:
  681. case ZEND_SEND_FUNC_ARG:
  682. opline->extended_value = 0;
  683. opline->opcode = ZEND_SEND_VAL_EX;
  684. break;
  685. case ZEND_SEND_VAR_NO_REF:
  686. return 0;
  687. case ZEND_SEND_VAR_NO_REF_EX:
  688. opline->opcode = ZEND_SEND_VAL;
  689. break;
  690. case ZEND_SEND_USER:
  691. opline->opcode = ZEND_SEND_VAL_EX;
  692. break;
  693. /* In most cases IS_TMP_VAR operand may be used only once.
  694. * The operands are usually destroyed by the opcode handler.
  695. * ZEND_CASE and ZEND_FETCH_LIST_R are exceptions, they keeps operand
  696. * unchanged, and allows its reuse. these instructions
  697. * usually terminated by ZEND_FREE that finally kills the value.
  698. */
  699. case ZEND_FETCH_LIST_R: {
  700. zend_op *m = opline;
  701. do {
  702. if (m->opcode == ZEND_FETCH_LIST_R &&
  703. m->op1_type == type &&
  704. m->op1.var == var) {
  705. zval v;
  706. ZVAL_COPY(&v, val);
  707. if (Z_TYPE(v) == IS_STRING) {
  708. zend_string_hash_val(Z_STR(v));
  709. }
  710. m->op1.constant = zend_optimizer_add_literal(op_array, &v);
  711. m->op1_type = IS_CONST;
  712. }
  713. m++;
  714. } while (m->opcode != ZEND_FREE || m->op1_type != type || m->op1.var != var);
  715. ZEND_ASSERT(m->opcode == ZEND_FREE && m->op1_type == type && m->op1.var == var);
  716. MAKE_NOP(m);
  717. zval_ptr_dtor_nogc(val);
  718. zend_optimizer_remove_live_range(op_array, var);
  719. return 1;
  720. }
  721. case ZEND_SWITCH_LONG:
  722. case ZEND_SWITCH_STRING:
  723. case ZEND_CASE:
  724. case ZEND_FREE: {
  725. zend_op *m, *n;
  726. int brk = op_array->last_live_range;
  727. zend_bool in_switch = 0;
  728. while (brk--) {
  729. if (op_array->live_range[brk].start <= (uint32_t)(opline - op_array->opcodes) &&
  730. op_array->live_range[brk].end > (uint32_t)(opline - op_array->opcodes)) {
  731. in_switch = 1;
  732. break;
  733. }
  734. }
  735. if (!in_switch) {
  736. ZEND_ASSERT(opline->opcode == ZEND_FREE);
  737. MAKE_NOP(opline);
  738. zval_ptr_dtor_nogc(val);
  739. return 1;
  740. }
  741. m = opline;
  742. n = op_array->opcodes + op_array->live_range[brk].end;
  743. if (n->opcode == ZEND_FREE &&
  744. !(n->extended_value & ZEND_FREE_ON_RETURN)) {
  745. n++;
  746. } else {
  747. n = op_array->opcodes + op_array->last;
  748. }
  749. while (m < n) {
  750. if (m->op1_type == type &&
  751. m->op1.var == var) {
  752. if (m->opcode == ZEND_CASE
  753. || m->opcode == ZEND_SWITCH_LONG
  754. || m->opcode == ZEND_SWITCH_STRING) {
  755. zval v;
  756. if (m->opcode == ZEND_CASE) {
  757. m->opcode = ZEND_IS_EQUAL;
  758. }
  759. ZVAL_COPY(&v, val);
  760. if (Z_TYPE(v) == IS_STRING) {
  761. zend_string_hash_val(Z_STR(v));
  762. }
  763. m->op1.constant = zend_optimizer_add_literal(op_array, &v);
  764. m->op1_type = IS_CONST;
  765. } else if (m->opcode == ZEND_FREE) {
  766. MAKE_NOP(m);
  767. } else {
  768. ZEND_ASSERT(0);
  769. }
  770. }
  771. m++;
  772. }
  773. zval_ptr_dtor_nogc(val);
  774. zend_optimizer_remove_live_range(op_array, var);
  775. return 1;
  776. }
  777. case ZEND_VERIFY_RETURN_TYPE: {
  778. zend_arg_info *ret_info = op_array->arg_info - 1;
  779. if (ZEND_TYPE_IS_CLASS(ret_info->type)
  780. || ZEND_TYPE_CODE(ret_info->type) == IS_CALLABLE
  781. || !ZEND_SAME_FAKE_TYPE(ZEND_TYPE_CODE(ret_info->type), Z_TYPE_P(val))
  782. || (op_array->fn_flags & ZEND_ACC_RETURN_REFERENCE)) {
  783. return 0;
  784. }
  785. MAKE_NOP(opline);
  786. /* zend_handle_loops_and_finally may inserts other oplines */
  787. do {
  788. ++opline;
  789. } while (opline->opcode != ZEND_RETURN && opline->opcode != ZEND_RETURN_BY_REF);
  790. ZEND_ASSERT(opline->op1.var == var);
  791. break;
  792. }
  793. default:
  794. break;
  795. }
  796. if (zend_optimizer_update_op1_const(op_array, opline, val)) {
  797. zend_optimizer_remove_live_range(op_array, var);
  798. return 1;
  799. }
  800. return 0;
  801. }
  802. if (opline->op2_type == type &&
  803. opline->op2.var == var) {
  804. if (zend_optimizer_update_op2_const(op_array, opline, val)) {
  805. zend_optimizer_remove_live_range(op_array, var);
  806. return 1;
  807. }
  808. return 0;
  809. }
  810. opline++;
  811. }
  812. return 1;
  813. }
  814. /* Update jump offsets after a jump was migrated to another opline */
  815. void zend_optimizer_migrate_jump(zend_op_array *op_array, zend_op *new_opline, zend_op *opline) {
  816. switch (new_opline->opcode) {
  817. case ZEND_JMP:
  818. case ZEND_FAST_CALL:
  819. ZEND_SET_OP_JMP_ADDR(new_opline, new_opline->op1, ZEND_OP1_JMP_ADDR(opline));
  820. break;
  821. case ZEND_JMPZNZ:
  822. new_opline->extended_value = ZEND_OPLINE_NUM_TO_OFFSET(op_array, new_opline, ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value));
  823. /* break missing intentionally */
  824. case ZEND_JMPZ:
  825. case ZEND_JMPNZ:
  826. case ZEND_JMPZ_EX:
  827. case ZEND_JMPNZ_EX:
  828. case ZEND_FE_RESET_R:
  829. case ZEND_FE_RESET_RW:
  830. case ZEND_JMP_SET:
  831. case ZEND_COALESCE:
  832. case ZEND_ASSERT_CHECK:
  833. ZEND_SET_OP_JMP_ADDR(new_opline, new_opline->op2, ZEND_OP2_JMP_ADDR(opline));
  834. break;
  835. case ZEND_DECLARE_ANON_CLASS:
  836. case ZEND_DECLARE_ANON_INHERITED_CLASS:
  837. case ZEND_FE_FETCH_R:
  838. case ZEND_FE_FETCH_RW:
  839. new_opline->extended_value = ZEND_OPLINE_NUM_TO_OFFSET(op_array, new_opline, ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value));
  840. break;
  841. case ZEND_CATCH:
  842. if (!(opline->extended_value & ZEND_LAST_CATCH)) {
  843. ZEND_SET_OP_JMP_ADDR(new_opline, new_opline->op2, ZEND_OP2_JMP_ADDR(opline));
  844. }
  845. break;
  846. case ZEND_SWITCH_LONG:
  847. case ZEND_SWITCH_STRING:
  848. {
  849. HashTable *jumptable = Z_ARRVAL(ZEND_OP2_LITERAL(opline));
  850. zval *zv;
  851. ZEND_HASH_FOREACH_VAL(jumptable, zv) {
  852. Z_LVAL_P(zv) = ZEND_OPLINE_NUM_TO_OFFSET(op_array, new_opline, ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, Z_LVAL_P(zv)));
  853. } ZEND_HASH_FOREACH_END();
  854. new_opline->extended_value = ZEND_OPLINE_NUM_TO_OFFSET(op_array, new_opline, ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value));
  855. break;
  856. }
  857. }
  858. }
  859. /* Shift jump offsets based on shiftlist */
  860. void zend_optimizer_shift_jump(zend_op_array *op_array, zend_op *opline, uint32_t *shiftlist) {
  861. switch (opline->opcode) {
  862. case ZEND_JMP:
  863. case ZEND_FAST_CALL:
  864. ZEND_SET_OP_JMP_ADDR(opline, opline->op1, ZEND_OP1_JMP_ADDR(opline) - shiftlist[ZEND_OP1_JMP_ADDR(opline) - op_array->opcodes]);
  865. break;
  866. case ZEND_JMPZNZ:
  867. opline->extended_value = ZEND_OPLINE_NUM_TO_OFFSET(op_array, opline, ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value) - shiftlist[ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value)]);
  868. /* break missing intentionally */
  869. case ZEND_JMPZ:
  870. case ZEND_JMPNZ:
  871. case ZEND_JMPZ_EX:
  872. case ZEND_JMPNZ_EX:
  873. case ZEND_FE_RESET_R:
  874. case ZEND_FE_RESET_RW:
  875. case ZEND_JMP_SET:
  876. case ZEND_COALESCE:
  877. case ZEND_ASSERT_CHECK:
  878. ZEND_SET_OP_JMP_ADDR(opline, opline->op2, ZEND_OP2_JMP_ADDR(opline) - shiftlist[ZEND_OP2_JMP_ADDR(opline) - op_array->opcodes]);
  879. break;
  880. case ZEND_CATCH:
  881. if (!(opline->extended_value & ZEND_LAST_CATCH)) {
  882. ZEND_SET_OP_JMP_ADDR(opline, opline->op2, ZEND_OP2_JMP_ADDR(opline) - shiftlist[ZEND_OP2_JMP_ADDR(opline) - op_array->opcodes]);
  883. }
  884. break;
  885. case ZEND_DECLARE_ANON_CLASS:
  886. case ZEND_DECLARE_ANON_INHERITED_CLASS:
  887. case ZEND_FE_FETCH_R:
  888. case ZEND_FE_FETCH_RW:
  889. opline->extended_value = ZEND_OPLINE_NUM_TO_OFFSET(op_array, opline, ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value) - shiftlist[ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value)]);
  890. break;
  891. case ZEND_SWITCH_LONG:
  892. case ZEND_SWITCH_STRING:
  893. {
  894. HashTable *jumptable = Z_ARRVAL(ZEND_OP2_LITERAL(opline));
  895. zval *zv;
  896. ZEND_HASH_FOREACH_VAL(jumptable, zv) {
  897. Z_LVAL_P(zv) = ZEND_OPLINE_NUM_TO_OFFSET(op_array, opline, ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, Z_LVAL_P(zv)) - shiftlist[ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, Z_LVAL_P(zv))]);
  898. } ZEND_HASH_FOREACH_END();
  899. opline->extended_value = ZEND_OPLINE_NUM_TO_OFFSET(op_array, opline, ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value) - shiftlist[ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value)]);
  900. break;
  901. }
  902. }
  903. }
  904. static zend_class_entry *get_class_entry_from_op1(
  905. zend_script *script, zend_op_array *op_array, zend_op *opline, zend_bool rt_constants) {
  906. if (opline->op1_type == IS_CONST) {
  907. zval *op1 = CRT_CONSTANT_EX(op_array, opline, opline->op1, rt_constants);
  908. if (Z_TYPE_P(op1) == IS_STRING) {
  909. zend_string *class_name = Z_STR_P(op1 + 1);
  910. zend_class_entry *ce;
  911. if (script && (ce = zend_hash_find_ptr(&script->class_table, class_name))) {
  912. return ce;
  913. } else if ((ce = zend_hash_find_ptr(EG(class_table), class_name))) {
  914. if (ce->type == ZEND_INTERNAL_CLASS) {
  915. return ce;
  916. } else if (ce->type == ZEND_USER_CLASS &&
  917. ce->info.user.filename &&
  918. ce->info.user.filename == op_array->filename) {
  919. return ce;
  920. }
  921. }
  922. }
  923. } else if (opline->op1_type == IS_UNUSED && op_array->scope
  924. && !(op_array->scope->ce_flags & ZEND_ACC_TRAIT)
  925. && (opline->op1.num & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_SELF) {
  926. return op_array->scope;
  927. }
  928. return NULL;
  929. }
  930. zend_function *zend_optimizer_get_called_func(
  931. zend_script *script, zend_op_array *op_array, zend_op *opline, zend_bool rt_constants)
  932. {
  933. #define GET_OP(op) CRT_CONSTANT_EX(op_array, opline, opline->op, rt_constants)
  934. switch (opline->opcode) {
  935. case ZEND_INIT_FCALL:
  936. {
  937. zend_string *function_name = Z_STR_P(GET_OP(op2));
  938. zend_function *func;
  939. if (script && (func = zend_hash_find_ptr(&script->function_table, function_name)) != NULL) {
  940. return func;
  941. } else if ((func = zend_hash_find_ptr(EG(function_table), function_name)) != NULL) {
  942. if (func->type == ZEND_INTERNAL_FUNCTION) {
  943. return func;
  944. } else if (func->type == ZEND_USER_FUNCTION &&
  945. func->op_array.filename &&
  946. func->op_array.filename == op_array->filename) {
  947. return func;
  948. }
  949. }
  950. break;
  951. }
  952. case ZEND_INIT_FCALL_BY_NAME:
  953. case ZEND_INIT_NS_FCALL_BY_NAME:
  954. if (opline->op2_type == IS_CONST && Z_TYPE_P(GET_OP(op2)) == IS_STRING) {
  955. zval *function_name = GET_OP(op2) + 1;
  956. zend_function *func;
  957. if (script && (func = zend_hash_find_ptr(&script->function_table, Z_STR_P(function_name)))) {
  958. return func;
  959. } else if ((func = zend_hash_find_ptr(EG(function_table), Z_STR_P(function_name))) != NULL) {
  960. if (func->type == ZEND_INTERNAL_FUNCTION) {
  961. return func;
  962. } else if (func->type == ZEND_USER_FUNCTION &&
  963. func->op_array.filename &&
  964. func->op_array.filename == op_array->filename) {
  965. return func;
  966. }
  967. }
  968. }
  969. break;
  970. case ZEND_INIT_STATIC_METHOD_CALL:
  971. if (opline->op2_type == IS_CONST && Z_TYPE_P(GET_OP(op2)) == IS_STRING) {
  972. zend_class_entry *ce = get_class_entry_from_op1(
  973. script, op_array, opline, rt_constants);
  974. if (ce) {
  975. zend_string *func_name = Z_STR_P(GET_OP(op2) + 1);
  976. return zend_hash_find_ptr(&ce->function_table, func_name);
  977. }
  978. }
  979. break;
  980. case ZEND_INIT_METHOD_CALL:
  981. if (opline->op1_type == IS_UNUSED
  982. && opline->op2_type == IS_CONST && Z_TYPE_P(GET_OP(op2)) == IS_STRING
  983. && op_array->scope && !(op_array->scope->ce_flags & ZEND_ACC_TRAIT)) {
  984. zend_string *method_name = Z_STR_P(GET_OP(op2) + 1);
  985. zend_function *fbc = zend_hash_find_ptr(
  986. &op_array->scope->function_table, method_name);
  987. if (fbc) {
  988. zend_bool is_private = (fbc->common.fn_flags & ZEND_ACC_PRIVATE) != 0;
  989. zend_bool is_final = (fbc->common.fn_flags & ZEND_ACC_FINAL) != 0;
  990. zend_bool same_scope = fbc->common.scope == op_array->scope;
  991. if ((is_private && same_scope)
  992. || (is_final && (!is_private || same_scope))) {
  993. return fbc;
  994. }
  995. }
  996. }
  997. break;
  998. case ZEND_NEW:
  999. {
  1000. zend_class_entry *ce = get_class_entry_from_op1(
  1001. script, op_array, opline, rt_constants);
  1002. if (ce && ce->type == ZEND_USER_CLASS) {
  1003. return ce->constructor;
  1004. }
  1005. break;
  1006. }
  1007. }
  1008. return NULL;
  1009. #undef GET_OP
  1010. }
  1011. uint32_t zend_optimizer_classify_function(zend_string *name, uint32_t num_args) {
  1012. if (zend_string_equals_literal(name, "extract")) {
  1013. return ZEND_FUNC_INDIRECT_VAR_ACCESS;
  1014. } else if (zend_string_equals_literal(name, "compact")) {
  1015. return ZEND_FUNC_INDIRECT_VAR_ACCESS;
  1016. } else if (zend_string_equals_literal(name, "parse_str") && num_args <= 1) {
  1017. return ZEND_FUNC_INDIRECT_VAR_ACCESS;
  1018. } else if (zend_string_equals_literal(name, "mb_parse_str") && num_args <= 1) {
  1019. return ZEND_FUNC_INDIRECT_VAR_ACCESS;
  1020. } else if (zend_string_equals_literal(name, "get_defined_vars")) {
  1021. return ZEND_FUNC_INDIRECT_VAR_ACCESS;
  1022. } else if (zend_string_equals_literal(name, "assert")) {
  1023. return ZEND_FUNC_INDIRECT_VAR_ACCESS;
  1024. } else if (zend_string_equals_literal(name, "db2_execute")) {
  1025. return ZEND_FUNC_INDIRECT_VAR_ACCESS;
  1026. } else if (zend_string_equals_literal(name, "func_num_args")) {
  1027. return ZEND_FUNC_VARARG;
  1028. } else if (zend_string_equals_literal(name, "func_get_arg")) {
  1029. return ZEND_FUNC_VARARG;
  1030. } else if (zend_string_equals_literal(name, "func_get_args")) {
  1031. return ZEND_FUNC_VARARG;
  1032. } else {
  1033. return 0;
  1034. }
  1035. }
  1036. static void zend_optimize(zend_op_array *op_array,
  1037. zend_optimizer_ctx *ctx)
  1038. {
  1039. if (op_array->type == ZEND_EVAL_CODE) {
  1040. return;
  1041. }
  1042. if (ctx->debug_level & ZEND_DUMP_BEFORE_OPTIMIZER) {
  1043. zend_dump_op_array(op_array, 0, "before optimizer", NULL);
  1044. }
  1045. /* pass 1
  1046. * - substitute persistent constants (true, false, null, etc)
  1047. * - perform compile-time evaluation of constant binary and unary operations
  1048. * - optimize series of ADD_STRING and/or ADD_CHAR
  1049. * - convert CAST(IS_BOOL,x) into BOOL(x)
  1050. * - pre-evaluate constant function calls
  1051. */
  1052. if (ZEND_OPTIMIZER_PASS_1 & ctx->optimization_level) {
  1053. zend_optimizer_pass1(op_array, ctx);
  1054. if (ctx->debug_level & ZEND_DUMP_AFTER_PASS_1) {
  1055. zend_dump_op_array(op_array, 0, "after pass 1", NULL);
  1056. }
  1057. }
  1058. /* pass 2:
  1059. * - convert non-numeric constants to numeric constants in numeric operators
  1060. * - optimize constant conditional JMPs
  1061. */
  1062. if (ZEND_OPTIMIZER_PASS_2 & ctx->optimization_level) {
  1063. zend_optimizer_pass2(op_array);
  1064. if (ctx->debug_level & ZEND_DUMP_AFTER_PASS_2) {
  1065. zend_dump_op_array(op_array, 0, "after pass 2", NULL);
  1066. }
  1067. }
  1068. /* pass 3:
  1069. * - optimize $i = $i+expr to $i+=expr
  1070. * - optimize series of JMPs
  1071. * - change $i++ to ++$i where possible
  1072. */
  1073. if (ZEND_OPTIMIZER_PASS_3 & ctx->optimization_level) {
  1074. zend_optimizer_pass3(op_array, ctx);
  1075. if (ctx->debug_level & ZEND_DUMP_AFTER_PASS_3) {
  1076. zend_dump_op_array(op_array, 0, "after pass 3", NULL);
  1077. }
  1078. }
  1079. /* pass 4:
  1080. * - INIT_FCALL_BY_NAME -> DO_FCALL
  1081. */
  1082. if (ZEND_OPTIMIZER_PASS_4 & ctx->optimization_level) {
  1083. zend_optimize_func_calls(op_array, ctx);
  1084. if (ctx->debug_level & ZEND_DUMP_AFTER_PASS_4) {
  1085. zend_dump_op_array(op_array, 0, "after pass 4", NULL);
  1086. }
  1087. }
  1088. /* pass 5:
  1089. * - CFG optimization
  1090. */
  1091. if (ZEND_OPTIMIZER_PASS_5 & ctx->optimization_level) {
  1092. zend_optimize_cfg(op_array, ctx);
  1093. if (ctx->debug_level & ZEND_DUMP_AFTER_PASS_5) {
  1094. zend_dump_op_array(op_array, 0, "after pass 5", NULL);
  1095. }
  1096. }
  1097. #if HAVE_DFA_PASS
  1098. /* pass 6:
  1099. * - DFA optimization
  1100. */
  1101. if ((ZEND_OPTIMIZER_PASS_6 & ctx->optimization_level) &&
  1102. !(ZEND_OPTIMIZER_PASS_7 & ctx->optimization_level)) {
  1103. zend_optimize_dfa(op_array, ctx);
  1104. if (ctx->debug_level & ZEND_DUMP_AFTER_PASS_6) {
  1105. zend_dump_op_array(op_array, 0, "after pass 6", NULL);
  1106. }
  1107. }
  1108. #endif
  1109. /* pass 9:
  1110. * - Optimize temp variables usage
  1111. */
  1112. if (ZEND_OPTIMIZER_PASS_9 & ctx->optimization_level) {
  1113. zend_optimize_temporary_variables(op_array, ctx);
  1114. if (ctx->debug_level & ZEND_DUMP_AFTER_PASS_9) {
  1115. zend_dump_op_array(op_array, 0, "after pass 9", NULL);
  1116. }
  1117. }
  1118. /* pass 10:
  1119. * - remove NOPs
  1120. */
  1121. if (((ZEND_OPTIMIZER_PASS_10|ZEND_OPTIMIZER_PASS_5) & ctx->optimization_level) == ZEND_OPTIMIZER_PASS_10) {
  1122. zend_optimizer_nop_removal(op_array, ctx);
  1123. if (ctx->debug_level & ZEND_DUMP_AFTER_PASS_10) {
  1124. zend_dump_op_array(op_array, 0, "after pass 10", NULL);
  1125. }
  1126. }
  1127. /* pass 11:
  1128. * - Compact literals table
  1129. */
  1130. if ((ZEND_OPTIMIZER_PASS_11 & ctx->optimization_level) &&
  1131. (!(ZEND_OPTIMIZER_PASS_6 & ctx->optimization_level) ||
  1132. !(ZEND_OPTIMIZER_PASS_7 & ctx->optimization_level))) {
  1133. zend_optimizer_compact_literals(op_array, ctx);
  1134. if (ctx->debug_level & ZEND_DUMP_AFTER_PASS_11) {
  1135. zend_dump_op_array(op_array, 0, "after pass 11", NULL);
  1136. }
  1137. }
  1138. if ((ZEND_OPTIMIZER_PASS_13 & ctx->optimization_level) &&
  1139. (!(ZEND_OPTIMIZER_PASS_6 & ctx->optimization_level) ||
  1140. !(ZEND_OPTIMIZER_PASS_7 & ctx->optimization_level))) {
  1141. zend_optimizer_compact_vars(op_array);
  1142. if (ctx->debug_level & ZEND_DUMP_AFTER_PASS_13) {
  1143. zend_dump_op_array(op_array, 0, "after pass 13", NULL);
  1144. }
  1145. }
  1146. if (ZEND_OPTIMIZER_PASS_7 & ctx->optimization_level) {
  1147. return;
  1148. }
  1149. if (ctx->debug_level & ZEND_DUMP_AFTER_OPTIMIZER) {
  1150. zend_dump_op_array(op_array, 0, "after optimizer", NULL);
  1151. }
  1152. }
  1153. static void zend_revert_pass_two(zend_op_array *op_array)
  1154. {
  1155. zend_op *opline, *end;
  1156. opline = op_array->opcodes;
  1157. end = opline + op_array->last;
  1158. while (opline < end) {
  1159. if (opline->op1_type == IS_CONST) {
  1160. ZEND_PASS_TWO_UNDO_CONSTANT(op_array, opline, opline->op1);
  1161. }
  1162. if (opline->op2_type == IS_CONST) {
  1163. ZEND_PASS_TWO_UNDO_CONSTANT(op_array, opline, opline->op2);
  1164. }
  1165. opline++;
  1166. }
  1167. #if !ZEND_USE_ABS_CONST_ADDR
  1168. if (op_array->literals) {
  1169. zval *literals = emalloc(sizeof(zval) * op_array->last_literal);
  1170. memcpy(literals, op_array->literals, sizeof(zval) * op_array->last_literal);
  1171. op_array->literals = literals;
  1172. }
  1173. #endif
  1174. }
  1175. static void zend_redo_pass_two(zend_op_array *op_array)
  1176. {
  1177. zend_op *opline, *end;
  1178. #if ZEND_USE_ABS_JMP_ADDR && !ZEND_USE_ABS_CONST_ADDR
  1179. zend_op *old_opcodes = op_array->opcodes;
  1180. #endif
  1181. #if !ZEND_USE_ABS_CONST_ADDR
  1182. if (op_array->last_literal) {
  1183. op_array->opcodes = (zend_op *) erealloc(op_array->opcodes,
  1184. ZEND_MM_ALIGNED_SIZE_EX(sizeof(zend_op) * op_array->last, 16) +
  1185. sizeof(zval) * op_array->last_literal);
  1186. memcpy(((char*)op_array->opcodes) + ZEND_MM_ALIGNED_SIZE_EX(sizeof(zend_op) * op_array->last, 16),
  1187. op_array->literals, sizeof(zval) * op_array->last_literal);
  1188. efree(op_array->literals);
  1189. op_array->literals = (zval*)(((char*)op_array->opcodes) + ZEND_MM_ALIGNED_SIZE_EX(sizeof(zend_op) * op_array->last, 16));
  1190. } else {
  1191. if (op_array->literals) {
  1192. efree(op_array->literals);
  1193. }
  1194. op_array->literals = NULL;
  1195. }
  1196. #endif
  1197. opline = op_array->opcodes;
  1198. end = opline + op_array->last;
  1199. while (opline < end) {
  1200. if (opline->op1_type == IS_CONST) {
  1201. ZEND_PASS_TWO_UPDATE_CONSTANT(op_array, opline, opline->op1);
  1202. }
  1203. if (opline->op2_type == IS_CONST) {
  1204. ZEND_PASS_TWO_UPDATE_CONSTANT(op_array, opline, opline->op2);
  1205. }
  1206. #if ZEND_USE_ABS_JMP_ADDR && !ZEND_USE_ABS_CONST_ADDR
  1207. if (op_array->fn_flags & ZEND_ACC_DONE_PASS_TWO) {
  1208. /* fix jumps to point to new array */
  1209. switch (opline->opcode) {
  1210. case ZEND_JMP:
  1211. case ZEND_FAST_CALL:
  1212. opline->op1.jmp_addr = &op_array->opcodes[opline->op1.jmp_addr - old_opcodes];
  1213. break;
  1214. case ZEND_JMPZNZ:
  1215. /* relative extended_value don't have to be changed */
  1216. /* break omitted intentionally */
  1217. case ZEND_JMPZ:
  1218. case ZEND_JMPNZ:
  1219. case ZEND_JMPZ_EX:
  1220. case ZEND_JMPNZ_EX:
  1221. case ZEND_JMP_SET:
  1222. case ZEND_COALESCE:
  1223. case ZEND_FE_RESET_R:
  1224. case ZEND_FE_RESET_RW:
  1225. case ZEND_ASSERT_CHECK:
  1226. opline->op2.jmp_addr = &op_array->opcodes[opline->op2.jmp_addr - old_opcodes];
  1227. break;
  1228. case ZEND_CATCH:
  1229. if (!(opline->extended_value & ZEND_LAST_CATCH)) {
  1230. opline->op2.jmp_addr = &op_array->opcodes[opline->op2.jmp_addr - old_opcodes];
  1231. }
  1232. break;
  1233. case ZEND_DECLARE_ANON_CLASS:
  1234. case ZEND_DECLARE_ANON_INHERITED_CLASS:
  1235. case ZEND_FE_FETCH_R:
  1236. case ZEND_FE_FETCH_RW:
  1237. case ZEND_SWITCH_LONG:
  1238. case ZEND_SWITCH_STRING:
  1239. /* relative extended_value don't have to be changed */
  1240. break;
  1241. }
  1242. }
  1243. #endif
  1244. ZEND_VM_SET_OPCODE_HANDLER(opline);
  1245. opline++;
  1246. }
  1247. }
  1248. #if HAVE_DFA_PASS
  1249. static void zend_redo_pass_two_ex(zend_op_array *op_array, zend_ssa *ssa)
  1250. {
  1251. zend_op *opline, *end;
  1252. #if ZEND_USE_ABS_JMP_ADDR && !ZEND_USE_ABS_CONST_ADDR
  1253. zend_op *old_opcodes = op_array->opcodes;
  1254. #endif
  1255. #if !ZEND_USE_ABS_CONST_ADDR
  1256. if (op_array->last_literal) {
  1257. op_array->opcodes = (zend_op *) erealloc(op_array->opcodes,
  1258. ZEND_MM_ALIGNED_SIZE_EX(sizeof(zend_op) * op_array->last, 16) +
  1259. sizeof(zval) * op_array->last_literal);
  1260. memcpy(((char*)op_array->opcodes) + ZEND_MM_ALIGNED_SIZE_EX(sizeof(zend_op) * op_array->last, 16),
  1261. op_array->literals, sizeof(zval) * op_array->last_literal);
  1262. efree(op_array->literals);
  1263. op_array->literals = (zval*)(((char*)op_array->opcodes) + ZEND_MM_ALIGNED_SIZE_EX(sizeof(zend_op) * op_array->last, 16));
  1264. } else {
  1265. if (op_array->literals) {
  1266. efree(op_array->literals);
  1267. }
  1268. op_array->literals = NULL;
  1269. }
  1270. #endif
  1271. opline = op_array->opcodes;
  1272. end = opline + op_array->last;
  1273. while (opline < end) {
  1274. uint32_t op1_info = opline->op1_type == IS_UNUSED ? 0 : (OP1_INFO() & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_KEY_ANY));
  1275. uint32_t op2_info = opline->op1_type == IS_UNUSED ? 0 : (OP2_INFO() & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_KEY_ANY));
  1276. uint32_t res_info =
  1277. (opline->opcode == ZEND_PRE_INC ||
  1278. opline->opcode == ZEND_PRE_DEC ||
  1279. opline->opcode == ZEND_POST_INC ||
  1280. opline->opcode == ZEND_POST_DEC) ?
  1281. ((ssa->ops[opline - op_array->opcodes].op1_def >= 0) ? (OP1_DEF_INFO() & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_KEY_ANY)) : MAY_BE_ANY) :
  1282. (opline->result_type == IS_UNUSED ? 0 : (RES_INFO() & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_KEY_ANY)));
  1283. if (opline->op1_type == IS_CONST) {
  1284. ZEND_PASS_TWO_UPDATE_CONSTANT(op_array, opline, opline->op1);
  1285. }
  1286. if (opline->op2_type == IS_CONST) {
  1287. ZEND_PASS_TWO_UPDATE_CONSTANT(op_array, opline, opline->op2);
  1288. }
  1289. zend_vm_set_opcode_handler_ex(opline, op1_info, op2_info, res_info);
  1290. #if ZEND_USE_ABS_JMP_ADDR && !ZEND_USE_ABS_CONST_ADDR
  1291. if (op_array->fn_flags & ZEND_ACC_DONE_PASS_TWO) {
  1292. /* fix jumps to point to new array */
  1293. switch (opline->opcode) {
  1294. case ZEND_JMP:
  1295. case ZEND_FAST_CALL:
  1296. opline->op1.jmp_addr = &op_array->opcodes[opline->op1.jmp_addr - old_opcodes];
  1297. break;
  1298. case ZEND_JMPZNZ:
  1299. /* relative extended_value don't have to be changed */
  1300. /* break omitted intentionally */
  1301. case ZEND_JMPZ:
  1302. case ZEND_JMPNZ:
  1303. case ZEND_JMPZ_EX:
  1304. case ZEND_JMPNZ_EX:
  1305. case ZEND_JMP_SET:
  1306. case ZEND_COALESCE:
  1307. case ZEND_FE_RESET_R:
  1308. case ZEND_FE_RESET_RW:
  1309. case ZEND_ASSERT_CHECK:
  1310. opline->op2.jmp_addr = &op_array->opcodes[opline->op2.jmp_addr - old_opcodes];
  1311. break;
  1312. case ZEND_CATCH:
  1313. if (!(opline->extended_value & ZEND_LAST_CATCH)) {
  1314. opline->op2.jmp_addr = &op_array->opcodes[opline->op2.jmp_addr - old_opcodes];
  1315. }
  1316. break;
  1317. case ZEND_DECLARE_ANON_CLASS:
  1318. case ZEND_DECLARE_ANON_INHERITED_CLASS:
  1319. case ZEND_FE_FETCH_R:
  1320. case ZEND_FE_FETCH_RW:
  1321. case ZEND_SWITCH_LONG:
  1322. case ZEND_SWITCH_STRING:
  1323. /* relative extended_value don't have to be changed */
  1324. break;
  1325. }
  1326. }
  1327. #endif
  1328. opline++;
  1329. }
  1330. }
  1331. #endif
  1332. static void zend_optimize_op_array(zend_op_array *op_array,
  1333. zend_optimizer_ctx *ctx)
  1334. {
  1335. /* Revert pass_two() */
  1336. zend_revert_pass_two(op_array);
  1337. /* Do actual optimizations */
  1338. zend_optimize(op_array, ctx);
  1339. /* Redo pass_two() */
  1340. zend_redo_pass_two(op_array);
  1341. }
  1342. static void zend_adjust_fcall_stack_size(zend_op_array *op_array, zend_optimizer_ctx *ctx)
  1343. {
  1344. zend_function *func;
  1345. zend_op *opline, *end;
  1346. opline = op_array->opcodes;
  1347. end = opline + op_array->last;
  1348. while (opline < end) {
  1349. if (opline->opcode == ZEND_INIT_FCALL) {
  1350. func = zend_hash_find_ptr(
  1351. &ctx->script->function_table,
  1352. Z_STR_P(RT_CONSTANT(opline, opline->op2)));
  1353. if (func) {
  1354. opline->op1.num = zend_vm_calc_used_stack(opline->extended_value, func);
  1355. }
  1356. }
  1357. opline++;
  1358. }
  1359. }
  1360. #if HAVE_DFA_PASS
  1361. static void zend_adjust_fcall_stack_size_graph(zend_op_array *op_array)
  1362. {
  1363. zend_func_info *func_info = ZEND_FUNC_INFO(op_array);
  1364. if (func_info) {
  1365. zend_call_info *call_info =func_info->callee_info;
  1366. while (call_info) {
  1367. zend_op *opline = call_info->caller_init_opline;
  1368. if (opline && call_info->callee_func && opline->opcode == ZEND_INIT_FCALL) {
  1369. opline->op1.num = zend_vm_calc_used_stack(opline->extended_value, call_info->callee_func);
  1370. }
  1371. call_info = call_info->next_callee;
  1372. }
  1373. }
  1374. }
  1375. #endif
  1376. int zend_optimize_script(zend_script *script, zend_long optimization_level, zend_long debug_level)
  1377. {
  1378. zend_class_entry *ce;
  1379. zend_op_array *op_array;
  1380. zend_string *name;
  1381. zend_optimizer_ctx ctx;
  1382. #if HAVE_DFA_PASS
  1383. zend_call_graph call_graph;
  1384. #endif
  1385. ctx.arena = zend_arena_create(64 * 1024);
  1386. ctx.script = script;
  1387. ctx.constants = NULL;
  1388. ctx.optimization_level = optimization_level;
  1389. ctx.debug_level = debug_level;
  1390. zend_optimize_op_array(&script->main_op_array, &ctx);
  1391. ZEND_HASH_FOREACH_PTR(&script->function_table, op_array) {
  1392. zend_optimize_op_array(op_array, &ctx);
  1393. } ZEND_HASH_FOREACH_END();
  1394. ZEND_HASH_FOREACH_PTR(&script->class_table, ce) {
  1395. ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->function_table, name, op_array) {
  1396. if (op_array->scope == ce) {
  1397. zend_optimize_op_array(op_array, &ctx);
  1398. } else if (op_array->type == ZEND_USER_FUNCTION) {
  1399. zend_op_array *orig_op_array;
  1400. if ((orig_op_array = zend_hash_find_ptr(&op_array->scope->function_table, name)) != NULL) {
  1401. HashTable *ht = op_array->static_variables;
  1402. *op_array = *orig_op_array;
  1403. op_array->static_variables = ht;
  1404. }
  1405. }
  1406. } ZEND_HASH_FOREACH_END();
  1407. } ZEND_HASH_FOREACH_END();
  1408. #if HAVE_DFA_PASS
  1409. if ((ZEND_OPTIMIZER_PASS_6 & optimization_level) &&
  1410. (ZEND_OPTIMIZER_PASS_7 & optimization_level) &&
  1411. zend_build_call_graph(&ctx.arena, script, ZEND_RT_CONSTANTS, &call_graph) == SUCCESS) {
  1412. /* Optimize using call-graph */
  1413. void *checkpoint = zend_arena_checkpoint(ctx.arena);
  1414. int i;
  1415. zend_func_info *func_info;
  1416. for (i = 0; i < call_graph.op_arrays_count; i++) {
  1417. zend_revert_pass_two(call_graph.op_arrays[i]);
  1418. }
  1419. for (i = 0; i < call_graph.op_arrays_count; i++) {
  1420. func_info = ZEND_FUNC_INFO(call_graph.op_arrays[i]);
  1421. if (func_info) {
  1422. func_info->call_map = zend_build_call_map(&ctx.arena, func_info, call_graph.op_arrays[i]);
  1423. if (call_graph.op_arrays[i]->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
  1424. zend_init_func_return_info(call_graph.op_arrays[i], script, &func_info->return_info);
  1425. }
  1426. }
  1427. }
  1428. for (i = 0; i < call_graph.op_arrays_count; i++) {
  1429. func_info = ZEND_FUNC_INFO(call_graph.op_arrays[i]);
  1430. if (func_info) {
  1431. if (zend_dfa_analyze_op_array(call_graph.op_arrays[i], &ctx, &func_info->ssa) == SUCCESS) {
  1432. func_info->flags = func_info->ssa.cfg.flags;
  1433. } else {
  1434. ZEND_SET_FUNC_INFO(call_graph.op_arrays[i], NULL);
  1435. }
  1436. }
  1437. }
  1438. //TODO: perform inner-script inference???
  1439. for (i = 0; i < call_graph.op_arrays_count; i++) {
  1440. func_info = ZEND_FUNC_INFO(call_graph.op_arrays[i]);
  1441. if (func_info) {
  1442. zend_dfa_optimize_op_array(call_graph.op_arrays[i], &ctx, &func_info->ssa, func_info->call_map);
  1443. }
  1444. }
  1445. if (debug_level & ZEND_DUMP_AFTER_PASS_7) {
  1446. for (i = 0; i < call_graph.op_arrays_count; i++) {
  1447. zend_dump_op_array(call_graph.op_arrays[i], 0, "after pass 7", NULL);
  1448. }
  1449. }
  1450. if (ZEND_OPTIMIZER_PASS_11 & optimization_level) {
  1451. for (i = 0; i < call_graph.op_arrays_count; i++) {
  1452. zend_optimizer_compact_literals(call_graph.op_arrays[i], &ctx);
  1453. if (debug_level & ZEND_DUMP_AFTER_PASS_11) {
  1454. zend_dump_op_array(call_graph.op_arrays[i], 0, "after pass 11", NULL);
  1455. }
  1456. }
  1457. }
  1458. if (ZEND_OPTIMIZER_PASS_13 & optimization_level) {
  1459. for (i = 0; i < call_graph.op_arrays_count; i++) {
  1460. zend_optimizer_compact_vars(call_graph.op_arrays[i]);
  1461. if (debug_level & ZEND_DUMP_AFTER_PASS_13) {
  1462. zend_dump_op_array(call_graph.op_arrays[i], 0, "after pass 13", NULL);
  1463. }
  1464. }
  1465. }
  1466. if (ZEND_OPTIMIZER_PASS_12 & optimization_level) {
  1467. for (i = 0; i < call_graph.op_arrays_count; i++) {
  1468. zend_adjust_fcall_stack_size_graph(call_graph.op_arrays[i]);
  1469. }
  1470. }
  1471. for (i = 0; i < call_graph.op_arrays_count; i++) {
  1472. func_info = ZEND_FUNC_INFO(call_graph.op_arrays[i]);
  1473. if (func_info && func_info->ssa.var_info) {
  1474. zend_redo_pass_two_ex(call_graph.op_arrays[i], &func_info->ssa);
  1475. } else {
  1476. zend_redo_pass_two(call_graph.op_arrays[i]);
  1477. }
  1478. }
  1479. for (i = 0; i < call_graph.op_arrays_count; i++) {
  1480. ZEND_SET_FUNC_INFO(call_graph.op_arrays[i], NULL);
  1481. }
  1482. ZEND_HASH_FOREACH_PTR(&script->class_table, ce) {
  1483. ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->function_table, name, op_array) {
  1484. if (op_array->scope != ce) {
  1485. zend_op_array *orig_op_array;
  1486. if ((orig_op_array = zend_hash_find_ptr(&op_array->scope->function_table, name)) != NULL) {
  1487. HashTable *ht = op_array->static_variables;
  1488. *op_array = *orig_op_array;
  1489. op_array->static_variables = ht;
  1490. }
  1491. }
  1492. } ZEND_HASH_FOREACH_END();
  1493. } ZEND_HASH_FOREACH_END();
  1494. zend_arena_release(&ctx.arena, checkpoint);
  1495. } else
  1496. #endif
  1497. if (ZEND_OPTIMIZER_PASS_12 & optimization_level) {
  1498. zend_adjust_fcall_stack_size(&script->main_op_array, &ctx);
  1499. ZEND_HASH_FOREACH_PTR(&script->function_table, op_array) {
  1500. zend_adjust_fcall_stack_size(op_array, &ctx);
  1501. } ZEND_HASH_FOREACH_END();
  1502. ZEND_HASH_FOREACH_PTR(&script->class_table, ce) {
  1503. ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->function_table, name, op_array) {
  1504. if (op_array->scope == ce) {
  1505. zend_adjust_fcall_stack_size(op_array, &ctx);
  1506. } else if (op_array->type == ZEND_USER_FUNCTION) {
  1507. zend_op_array *orig_op_array;
  1508. if ((orig_op_array = zend_hash_find_ptr(&op_array->scope->function_table, name)) != NULL) {
  1509. HashTable *ht = op_array->static_variables;
  1510. *op_array = *orig_op_array;
  1511. op_array->static_variables = ht;
  1512. }
  1513. }
  1514. } ZEND_HASH_FOREACH_END();
  1515. } ZEND_HASH_FOREACH_END();
  1516. }
  1517. if ((debug_level & ZEND_DUMP_AFTER_OPTIMIZER) &&
  1518. (ZEND_OPTIMIZER_PASS_7 & optimization_level)) {
  1519. zend_dump_op_array(&script->main_op_array, ZEND_DUMP_RT_CONSTANTS, "after optimizer", NULL);
  1520. ZEND_HASH_FOREACH_PTR(&script->function_table, op_array) {
  1521. zend_dump_op_array(op_array, ZEND_DUMP_RT_CONSTANTS, "after optimizer", NULL);
  1522. } ZEND_HASH_FOREACH_END();
  1523. ZEND_HASH_FOREACH_PTR(&script->class_table, ce) {
  1524. ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->function_table, name, op_array) {
  1525. if (op_array->scope == ce) {
  1526. zend_dump_op_array(op_array, ZEND_DUMP_RT_CONSTANTS, "after optimizer", NULL);
  1527. }
  1528. } ZEND_HASH_FOREACH_END();
  1529. } ZEND_HASH_FOREACH_END();
  1530. }
  1531. if (ctx.constants) {
  1532. zend_hash_destroy(ctx.constants);
  1533. }
  1534. zend_arena_destroy(ctx.arena);
  1535. return 1;
  1536. }
  1537. int zend_optimizer_startup(void)
  1538. {
  1539. return zend_func_info_startup();
  1540. }
  1541. int zend_optimizer_shutdown(void)
  1542. {
  1543. return zend_func_info_shutdown();
  1544. }
  1545. /*
  1546. * Local variables:
  1547. * tab-width: 4
  1548. * c-basic-offset: 4
  1549. * indent-tabs-mode: t
  1550. * End:
  1551. */