block_pass.c 61 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944
  1. /*
  2. +----------------------------------------------------------------------+
  3. | Zend OPcache |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 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. | https://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 "Optimizer/zend_optimizer.h"
  22. #include "Optimizer/zend_optimizer_internal.h"
  23. #include "zend_API.h"
  24. #include "zend_constants.h"
  25. #include "zend_execute.h"
  26. #include "zend_vm.h"
  27. #include "zend_bitset.h"
  28. #include "zend_cfg.h"
  29. #include "zend_dump.h"
  30. /* Checks if a constant (like "true") may be replaced by its value */
  31. int zend_optimizer_get_persistent_constant(zend_string *name, zval *result, int copy)
  32. {
  33. zend_constant *c = zend_hash_find_ptr(EG(zend_constants), name);
  34. if (c) {
  35. if ((ZEND_CONSTANT_FLAGS(c) & CONST_PERSISTENT)
  36. && !(ZEND_CONSTANT_FLAGS(c) & CONST_DEPRECATED)
  37. && (!(ZEND_CONSTANT_FLAGS(c) & CONST_NO_FILE_CACHE)
  38. || !(CG(compiler_options) & ZEND_COMPILE_WITH_FILE_CACHE))) {
  39. ZVAL_COPY_VALUE(result, &c->value);
  40. if (copy) {
  41. Z_TRY_ADDREF_P(result);
  42. }
  43. return 1;
  44. } else {
  45. return 0;
  46. }
  47. }
  48. /* Special constants null/true/false can always be substituted. */
  49. c = zend_get_special_const(ZSTR_VAL(name), ZSTR_LEN(name));
  50. if (c) {
  51. ZVAL_COPY_VALUE(result, &c->value);
  52. return 1;
  53. }
  54. return 0;
  55. }
  56. /* Data dependencies macros */
  57. #define VAR_SOURCE(op) Tsource[VAR_NUM(op.var)]
  58. #define SET_VAR_SOURCE(opline) Tsource[VAR_NUM(opline->result.var)] = opline
  59. static void strip_leading_nops(zend_op_array *op_array, zend_basic_block *b)
  60. {
  61. zend_op *opcodes = op_array->opcodes;
  62. do {
  63. b->start++;
  64. b->len--;
  65. } while (b->len > 0 && opcodes[b->start].opcode == ZEND_NOP);
  66. }
  67. static void strip_nops(zend_op_array *op_array, zend_basic_block *b)
  68. {
  69. uint32_t i, j;
  70. if (b->len == 0) {
  71. return;
  72. }
  73. if (op_array->opcodes[b->start].opcode == ZEND_NOP) {
  74. strip_leading_nops(op_array, b);
  75. }
  76. if (b->len == 0) {
  77. return;
  78. }
  79. /* strip the inside NOPs */
  80. i = j = b->start + 1;
  81. while (i < b->start + b->len) {
  82. if (op_array->opcodes[i].opcode != ZEND_NOP) {
  83. if (i != j) {
  84. op_array->opcodes[j] = op_array->opcodes[i];
  85. }
  86. j++;
  87. }
  88. i++;
  89. }
  90. b->len = j - b->start;
  91. while (j < i) {
  92. MAKE_NOP(op_array->opcodes + j);
  93. j++;
  94. }
  95. }
  96. static int get_const_switch_target(zend_cfg *cfg, zend_op_array *op_array, zend_basic_block *block, zend_op *opline, zval *val) {
  97. HashTable *jumptable = Z_ARRVAL(ZEND_OP2_LITERAL(opline));
  98. zval *zv;
  99. if ((opline->opcode == ZEND_SWITCH_LONG && Z_TYPE_P(val) != IS_LONG)
  100. || (opline->opcode == ZEND_SWITCH_STRING && Z_TYPE_P(val) != IS_STRING)) {
  101. /* fallback to next block */
  102. return block->successors[block->successors_count - 1];
  103. }
  104. if (opline->opcode == ZEND_MATCH && Z_TYPE_P(val) != IS_LONG && Z_TYPE_P(val) != IS_STRING) {
  105. /* always jump to the default arm */
  106. return block->successors[block->successors_count - 1];
  107. }
  108. if (Z_TYPE_P(val) == IS_LONG) {
  109. zv = zend_hash_index_find(jumptable, Z_LVAL_P(val));
  110. } else {
  111. ZEND_ASSERT(Z_TYPE_P(val) == IS_STRING);
  112. zv = zend_hash_find(jumptable, Z_STR_P(val));
  113. }
  114. if (!zv) {
  115. /* default */
  116. return block->successors[block->successors_count - (opline->opcode == ZEND_MATCH ? 1 : 2)];
  117. }
  118. return cfg->map[ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, Z_LVAL_P(zv))];
  119. }
  120. static void zend_optimize_block(zend_basic_block *block, zend_op_array *op_array, zend_bitset used_ext, zend_cfg *cfg, zend_op **Tsource, uint32_t *opt_count)
  121. {
  122. zend_op *opline, *src;
  123. zend_op *end, *last_op = NULL;
  124. if (block->len == 0) {
  125. return;
  126. }
  127. if (op_array->opcodes[block->start].opcode == ZEND_NOP) {
  128. /* remove leading NOPs */
  129. strip_leading_nops(op_array, block);
  130. }
  131. opline = op_array->opcodes + block->start;
  132. end = opline + block->len;
  133. while (opline < end) {
  134. /* Constant Propagation: strip X = QM_ASSIGN(const) */
  135. if (opline->op1_type == IS_TMP_VAR &&
  136. opline->opcode != ZEND_FREE) {
  137. src = VAR_SOURCE(opline->op1);
  138. if (src &&
  139. src->opcode == ZEND_QM_ASSIGN &&
  140. src->op1_type == IS_CONST
  141. ) {
  142. znode_op op1 = opline->op1;
  143. if (opline->opcode == ZEND_VERIFY_RETURN_TYPE) {
  144. COPY_NODE(opline->result, opline->op1);
  145. COPY_NODE(opline->op1, src->op1);
  146. VAR_SOURCE(op1) = NULL;
  147. MAKE_NOP(src);
  148. ++(*opt_count);
  149. } else {
  150. zval c;
  151. ZVAL_COPY(&c, &ZEND_OP1_LITERAL(src));
  152. if (opline->opcode != ZEND_CASE
  153. && opline->opcode != ZEND_CASE_STRICT
  154. && opline->opcode != ZEND_FETCH_LIST_R
  155. && opline->opcode != ZEND_SWITCH_LONG
  156. && opline->opcode != ZEND_SWITCH_STRING
  157. && opline->opcode != ZEND_MATCH
  158. && zend_optimizer_update_op1_const(op_array, opline, &c)) {
  159. VAR_SOURCE(op1) = NULL;
  160. literal_dtor(&ZEND_OP1_LITERAL(src));
  161. MAKE_NOP(src);
  162. ++(*opt_count);
  163. } else {
  164. zval_ptr_dtor_nogc(&c);
  165. }
  166. }
  167. }
  168. }
  169. /* Constant Propagation: strip X = QM_ASSIGN(const) */
  170. if (opline->op2_type == IS_TMP_VAR) {
  171. src = VAR_SOURCE(opline->op2);
  172. if (src &&
  173. src->opcode == ZEND_QM_ASSIGN &&
  174. src->op1_type == IS_CONST) {
  175. znode_op op2 = opline->op2;
  176. zval c;
  177. ZVAL_COPY(&c, &ZEND_OP1_LITERAL(src));
  178. if (zend_optimizer_update_op2_const(op_array, opline, &c)) {
  179. VAR_SOURCE(op2) = NULL;
  180. literal_dtor(&ZEND_OP1_LITERAL(src));
  181. MAKE_NOP(src);
  182. ++(*opt_count);
  183. } else {
  184. zval_ptr_dtor_nogc(&c);
  185. }
  186. }
  187. }
  188. switch (opline->opcode) {
  189. case ZEND_ECHO:
  190. if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) {
  191. src = VAR_SOURCE(opline->op1);
  192. if (src &&
  193. src->opcode == ZEND_CAST &&
  194. src->extended_value == IS_STRING) {
  195. /* T = CAST(X, String), ECHO(T) => NOP, ECHO(X) */
  196. VAR_SOURCE(opline->op1) = NULL;
  197. COPY_NODE(opline->op1, src->op1);
  198. MAKE_NOP(src);
  199. ++(*opt_count);
  200. }
  201. } else if (opline->op1_type == IS_CONST &&
  202. Z_TYPE(ZEND_OP1_LITERAL(opline)) != IS_DOUBLE) {
  203. if (last_op == opline - 1) {
  204. /* compress consecutive ECHO's.
  205. * Float to string conversion may be affected by current
  206. * locale setting.
  207. */
  208. int l, old_len;
  209. if (Z_TYPE(ZEND_OP1_LITERAL(opline)) != IS_STRING) {
  210. convert_to_string(&ZEND_OP1_LITERAL(opline));
  211. }
  212. if (Z_TYPE(ZEND_OP1_LITERAL(last_op)) != IS_STRING) {
  213. convert_to_string(&ZEND_OP1_LITERAL(last_op));
  214. }
  215. old_len = Z_STRLEN(ZEND_OP1_LITERAL(last_op));
  216. l = old_len + Z_STRLEN(ZEND_OP1_LITERAL(opline));
  217. if (!Z_REFCOUNTED(ZEND_OP1_LITERAL(last_op))) {
  218. zend_string *tmp = zend_string_alloc(l, 0);
  219. memcpy(ZSTR_VAL(tmp), Z_STRVAL(ZEND_OP1_LITERAL(last_op)), old_len);
  220. Z_STR(ZEND_OP1_LITERAL(last_op)) = tmp;
  221. } else {
  222. Z_STR(ZEND_OP1_LITERAL(last_op)) = zend_string_extend(Z_STR(ZEND_OP1_LITERAL(last_op)), l, 0);
  223. }
  224. Z_TYPE_INFO(ZEND_OP1_LITERAL(last_op)) = IS_STRING_EX;
  225. memcpy(Z_STRVAL(ZEND_OP1_LITERAL(last_op)) + old_len, Z_STRVAL(ZEND_OP1_LITERAL(opline)), Z_STRLEN(ZEND_OP1_LITERAL(opline)));
  226. Z_STRVAL(ZEND_OP1_LITERAL(last_op))[l] = '\0';
  227. zval_ptr_dtor_nogc(&ZEND_OP1_LITERAL(opline));
  228. ZVAL_STR(&ZEND_OP1_LITERAL(opline), zend_new_interned_string(Z_STR(ZEND_OP1_LITERAL(last_op))));
  229. ZVAL_NULL(&ZEND_OP1_LITERAL(last_op));
  230. MAKE_NOP(last_op);
  231. ++(*opt_count);
  232. }
  233. last_op = opline;
  234. }
  235. break;
  236. case ZEND_FREE:
  237. if (opline->op1_type == IS_TMP_VAR) {
  238. src = VAR_SOURCE(opline->op1);
  239. if (src) {
  240. switch (src->opcode) {
  241. case ZEND_BOOL:
  242. case ZEND_BOOL_NOT:
  243. /* T = BOOL(X), FREE(T) => T = BOOL(X) */
  244. /* The remaining BOOL is removed by a separate optimization */
  245. VAR_SOURCE(opline->op1) = NULL;
  246. MAKE_NOP(opline);
  247. ++(*opt_count);
  248. break;
  249. case ZEND_ASSIGN:
  250. case ZEND_ASSIGN_DIM:
  251. case ZEND_ASSIGN_OBJ:
  252. case ZEND_ASSIGN_STATIC_PROP:
  253. case ZEND_ASSIGN_OP:
  254. case ZEND_ASSIGN_DIM_OP:
  255. case ZEND_ASSIGN_OBJ_OP:
  256. case ZEND_ASSIGN_STATIC_PROP_OP:
  257. case ZEND_PRE_INC:
  258. case ZEND_PRE_DEC:
  259. case ZEND_PRE_INC_OBJ:
  260. case ZEND_PRE_DEC_OBJ:
  261. case ZEND_PRE_INC_STATIC_PROP:
  262. case ZEND_PRE_DEC_STATIC_PROP:
  263. src->result_type = IS_UNUSED;
  264. VAR_SOURCE(opline->op1) = NULL;
  265. MAKE_NOP(opline);
  266. ++(*opt_count);
  267. break;
  268. default:
  269. break;
  270. }
  271. }
  272. } else if (opline->op1_type == IS_VAR) {
  273. src = VAR_SOURCE(opline->op1);
  274. /* V = OP, FREE(V) => OP. NOP */
  275. if (src &&
  276. src->opcode != ZEND_FETCH_R &&
  277. src->opcode != ZEND_FETCH_STATIC_PROP_R &&
  278. src->opcode != ZEND_FETCH_DIM_R &&
  279. src->opcode != ZEND_FETCH_OBJ_R &&
  280. src->opcode != ZEND_NEW &&
  281. src->opcode != ZEND_FETCH_THIS) {
  282. src->result_type = IS_UNUSED;
  283. MAKE_NOP(opline);
  284. ++(*opt_count);
  285. if (src->opcode == ZEND_QM_ASSIGN) {
  286. if (src->op1_type & (IS_VAR|IS_TMP_VAR)) {
  287. src->opcode = ZEND_FREE;
  288. } else {
  289. MAKE_NOP(src);
  290. }
  291. }
  292. }
  293. }
  294. break;
  295. #if 0
  296. /* pre-evaluate functions:
  297. constant(x)
  298. function_exists(x)
  299. extension_loaded(x)
  300. BAD: interacts badly with Accelerator
  301. */
  302. if((opline->op1_type & IS_VAR) &&
  303. VAR_SOURCE(opline->op1) && VAR_SOURCE(opline->op1)->opcode == ZEND_DO_CF_FCALL &&
  304. VAR_SOURCE(opline->op1)->extended_value == 1) {
  305. zend_op *fcall = VAR_SOURCE(opline->op1);
  306. zend_op *sv = fcall-1;
  307. if(sv >= block->start_opline && sv->opcode == ZEND_SEND_VAL &&
  308. sv->op1_type == IS_CONST && Z_TYPE(OPLINE_OP1_LITERAL(sv)) == IS_STRING &&
  309. Z_LVAL(OPLINE_OP2_LITERAL(sv)) == 1
  310. ) {
  311. zval *arg = &OPLINE_OP1_LITERAL(sv);
  312. char *fname = FUNCTION_CACHE->funcs[Z_LVAL(ZEND_OP1_LITERAL(fcall))].function_name;
  313. int flen = FUNCTION_CACHE->funcs[Z_LVAL(ZEND_OP1_LITERAL(fcall))].name_len;
  314. if((flen == sizeof("function_exists")-1 && zend_binary_strcasecmp(fname, flen, "function_exists", sizeof("function_exists")-1) == 0) ||
  315. (flen == sizeof("is_callable")-1 && zend_binary_strcasecmp(fname, flen, "is_callable", sizeof("is_callable")-1) == 0)
  316. ) {
  317. zend_function *function;
  318. if((function = zend_hash_find_ptr(EG(function_table), Z_STR_P(arg))) != NULL) {
  319. literal_dtor(arg);
  320. MAKE_NOP(sv);
  321. MAKE_NOP(fcall);
  322. LITERAL_BOOL(opline->op1, 1);
  323. opline->op1_type = IS_CONST;
  324. }
  325. } else if(flen == sizeof("constant")-1 && zend_binary_strcasecmp(fname, flen, "constant", sizeof("constant")-1) == 0) {
  326. zval c;
  327. if(zend_optimizer_get_persistent_constant(Z_STR_P(arg), &c, 1 ELS_CC) != 0) {
  328. literal_dtor(arg);
  329. MAKE_NOP(sv);
  330. MAKE_NOP(fcall);
  331. ZEND_OP1_LITERAL(opline) = zend_optimizer_add_literal(op_array, &c);
  332. /* no copy ctor - get already copied it */
  333. opline->op1_type = IS_CONST;
  334. }
  335. } else if(flen == sizeof("extension_loaded")-1 && zend_binary_strcasecmp(fname, flen, "extension_loaded", sizeof("extension_loaded")-1) == 0) {
  336. if(zend_hash_exists(&module_registry, Z_STR_P(arg))) {
  337. literal_dtor(arg);
  338. MAKE_NOP(sv);
  339. MAKE_NOP(fcall);
  340. LITERAL_BOOL(opline->op1, 1);
  341. opline->op1_type = IS_CONST;
  342. }
  343. }
  344. }
  345. }
  346. #endif
  347. case ZEND_FETCH_LIST_R:
  348. case ZEND_FETCH_LIST_W:
  349. if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) {
  350. /* LIST variable will be deleted later by FREE */
  351. Tsource[VAR_NUM(opline->op1.var)] = NULL;
  352. }
  353. break;
  354. case ZEND_SWITCH_LONG:
  355. case ZEND_SWITCH_STRING:
  356. case ZEND_MATCH:
  357. if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) {
  358. /* SWITCH variable will be deleted later by FREE, so we can't optimize it */
  359. Tsource[VAR_NUM(opline->op1.var)] = NULL;
  360. break;
  361. }
  362. if (opline->op1_type == IS_CONST) {
  363. int target = get_const_switch_target(cfg, op_array, block, opline, &ZEND_OP1_LITERAL(opline));
  364. literal_dtor(&ZEND_OP1_LITERAL(opline));
  365. literal_dtor(&ZEND_OP2_LITERAL(opline));
  366. opline->opcode = ZEND_JMP;
  367. opline->op1_type = IS_UNUSED;
  368. opline->op2_type = IS_UNUSED;
  369. block->successors_count = 1;
  370. block->successors[0] = target;
  371. }
  372. break;
  373. case ZEND_CASE:
  374. case ZEND_CASE_STRICT:
  375. case ZEND_COPY_TMP:
  376. if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) {
  377. /* Variable will be deleted later by FREE, so we can't optimize it */
  378. Tsource[VAR_NUM(opline->op1.var)] = NULL;
  379. break;
  380. }
  381. ZEND_FALLTHROUGH;
  382. case ZEND_IS_EQUAL:
  383. case ZEND_IS_NOT_EQUAL:
  384. if (opline->op1_type == IS_CONST &&
  385. opline->op2_type == IS_CONST) {
  386. goto optimize_constant_binary_op;
  387. }
  388. /* IS_EQ(TRUE, X) => BOOL(X)
  389. * IS_EQ(FALSE, X) => BOOL_NOT(X)
  390. * IS_NOT_EQ(TRUE, X) => BOOL_NOT(X)
  391. * IS_NOT_EQ(FALSE, X) => BOOL(X)
  392. * CASE(TRUE, X) => BOOL(X)
  393. * CASE(FALSE, X) => BOOL_NOT(X)
  394. */
  395. if (opline->op1_type == IS_CONST &&
  396. (Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_FALSE ||
  397. Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_TRUE)) {
  398. /* Optimization of comparison with "null" is not safe,
  399. * because ("0" == null) is not equal to !("0")
  400. */
  401. opline->opcode =
  402. ((opline->opcode != ZEND_IS_NOT_EQUAL) == ((Z_TYPE(ZEND_OP1_LITERAL(opline))) == IS_TRUE)) ?
  403. ZEND_BOOL : ZEND_BOOL_NOT;
  404. COPY_NODE(opline->op1, opline->op2);
  405. SET_UNUSED(opline->op2);
  406. ++(*opt_count);
  407. goto optimize_bool;
  408. } else if (opline->op2_type == IS_CONST &&
  409. (Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_FALSE ||
  410. Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_TRUE)) {
  411. /* Optimization of comparison with "null" is not safe,
  412. * because ("0" == null) is not equal to !("0")
  413. */
  414. opline->opcode =
  415. ((opline->opcode != ZEND_IS_NOT_EQUAL) == ((Z_TYPE(ZEND_OP2_LITERAL(opline))) == IS_TRUE)) ?
  416. ZEND_BOOL : ZEND_BOOL_NOT;
  417. SET_UNUSED(opline->op2);
  418. ++(*opt_count);
  419. goto optimize_bool;
  420. }
  421. break;
  422. case ZEND_BOOL:
  423. case ZEND_BOOL_NOT:
  424. optimize_bool:
  425. if (opline->op1_type == IS_CONST) {
  426. goto optimize_const_unary_op;
  427. }
  428. if (opline->op1_type == IS_TMP_VAR &&
  429. !zend_bitset_in(used_ext, VAR_NUM(opline->op1.var))) {
  430. src = VAR_SOURCE(opline->op1);
  431. if (src) {
  432. switch (src->opcode) {
  433. case ZEND_BOOL_NOT:
  434. /* T = BOOL_NOT(X) + BOOL(T) -> NOP, BOOL_NOT(X) */
  435. VAR_SOURCE(opline->op1) = NULL;
  436. COPY_NODE(opline->op1, src->op1);
  437. opline->opcode = (opline->opcode == ZEND_BOOL) ? ZEND_BOOL_NOT : ZEND_BOOL;
  438. MAKE_NOP(src);
  439. ++(*opt_count);
  440. goto optimize_bool;
  441. case ZEND_BOOL:
  442. /* T = BOOL(X) + BOOL(T) -> NOP, BOOL(X) */
  443. VAR_SOURCE(opline->op1) = NULL;
  444. COPY_NODE(opline->op1, src->op1);
  445. MAKE_NOP(src);
  446. ++(*opt_count);
  447. goto optimize_bool;
  448. case ZEND_IS_EQUAL:
  449. if (opline->opcode == ZEND_BOOL_NOT) {
  450. src->opcode = ZEND_IS_NOT_EQUAL;
  451. }
  452. COPY_NODE(src->result, opline->result);
  453. SET_VAR_SOURCE(src);
  454. MAKE_NOP(opline);
  455. ++(*opt_count);
  456. break;
  457. case ZEND_IS_NOT_EQUAL:
  458. if (opline->opcode == ZEND_BOOL_NOT) {
  459. src->opcode = ZEND_IS_EQUAL;
  460. }
  461. COPY_NODE(src->result, opline->result);
  462. SET_VAR_SOURCE(src);
  463. MAKE_NOP(opline);
  464. ++(*opt_count);
  465. break;
  466. case ZEND_IS_IDENTICAL:
  467. if (opline->opcode == ZEND_BOOL_NOT) {
  468. src->opcode = ZEND_IS_NOT_IDENTICAL;
  469. }
  470. COPY_NODE(src->result, opline->result);
  471. SET_VAR_SOURCE(src);
  472. MAKE_NOP(opline);
  473. ++(*opt_count);
  474. break;
  475. case ZEND_IS_NOT_IDENTICAL:
  476. if (opline->opcode == ZEND_BOOL_NOT) {
  477. src->opcode = ZEND_IS_IDENTICAL;
  478. }
  479. COPY_NODE(src->result, opline->result);
  480. SET_VAR_SOURCE(src);
  481. MAKE_NOP(opline);
  482. ++(*opt_count);
  483. break;
  484. case ZEND_IS_SMALLER:
  485. if (opline->opcode == ZEND_BOOL_NOT) {
  486. zend_uchar tmp_type;
  487. uint32_t tmp;
  488. src->opcode = ZEND_IS_SMALLER_OR_EQUAL;
  489. tmp_type = src->op1_type;
  490. src->op1_type = src->op2_type;
  491. src->op2_type = tmp_type;
  492. tmp = src->op1.num;
  493. src->op1.num = src->op2.num;
  494. src->op2.num = tmp;
  495. }
  496. COPY_NODE(src->result, opline->result);
  497. SET_VAR_SOURCE(src);
  498. MAKE_NOP(opline);
  499. ++(*opt_count);
  500. break;
  501. case ZEND_IS_SMALLER_OR_EQUAL:
  502. if (opline->opcode == ZEND_BOOL_NOT) {
  503. zend_uchar tmp_type;
  504. uint32_t tmp;
  505. src->opcode = ZEND_IS_SMALLER;
  506. tmp_type = src->op1_type;
  507. src->op1_type = src->op2_type;
  508. src->op2_type = tmp_type;
  509. tmp = src->op1.num;
  510. src->op1.num = src->op2.num;
  511. src->op2.num = tmp;
  512. }
  513. COPY_NODE(src->result, opline->result);
  514. SET_VAR_SOURCE(src);
  515. MAKE_NOP(opline);
  516. ++(*opt_count);
  517. break;
  518. case ZEND_ISSET_ISEMPTY_CV:
  519. case ZEND_ISSET_ISEMPTY_VAR:
  520. case ZEND_ISSET_ISEMPTY_DIM_OBJ:
  521. case ZEND_ISSET_ISEMPTY_PROP_OBJ:
  522. case ZEND_ISSET_ISEMPTY_STATIC_PROP:
  523. case ZEND_INSTANCEOF:
  524. case ZEND_TYPE_CHECK:
  525. case ZEND_DEFINED:
  526. case ZEND_IN_ARRAY:
  527. case ZEND_ARRAY_KEY_EXISTS:
  528. if (opline->opcode == ZEND_BOOL_NOT) {
  529. break;
  530. }
  531. COPY_NODE(src->result, opline->result);
  532. SET_VAR_SOURCE(src);
  533. MAKE_NOP(opline);
  534. ++(*opt_count);
  535. break;
  536. }
  537. }
  538. }
  539. break;
  540. case ZEND_JMPZ:
  541. case ZEND_JMPNZ:
  542. while (1) {
  543. if (opline->op1_type == IS_CONST) {
  544. ++(*opt_count);
  545. block->successors_count = 1;
  546. if (zend_is_true(&ZEND_OP1_LITERAL(opline)) ==
  547. (opline->opcode == ZEND_JMPZ)) {
  548. MAKE_NOP(opline);
  549. block->successors[0] = block->successors[1];
  550. block->len--;
  551. cfg->blocks[block->successors[0]].flags |= ZEND_BB_FOLLOW;
  552. break;
  553. } else {
  554. zend_basic_block *next = cfg->blocks + block->successors[1];
  555. next->flags &= ~ZEND_BB_FOLLOW;
  556. if (!(next->flags & (ZEND_BB_TARGET|ZEND_BB_PROTECTED))) {
  557. next->flags &= ~ZEND_BB_REACHABLE;
  558. }
  559. opline->opcode = ZEND_JMP;
  560. COPY_NODE(opline->op1, opline->op2);
  561. break;
  562. }
  563. } else if (opline->op1_type == IS_TMP_VAR &&
  564. !zend_bitset_in(used_ext, VAR_NUM(opline->op1.var))) {
  565. src = VAR_SOURCE(opline->op1);
  566. if (src) {
  567. if (src->opcode == ZEND_BOOL_NOT) {
  568. VAR_SOURCE(opline->op1) = NULL;
  569. COPY_NODE(opline->op1, src->op1);
  570. /* T = BOOL_NOT(X) + JMPZ(T) -> NOP, JMPNZ(X) */
  571. opline->opcode = INV_COND(opline->opcode);
  572. MAKE_NOP(src);
  573. ++(*opt_count);
  574. continue;
  575. } else if (src->opcode == ZEND_BOOL ||
  576. src->opcode == ZEND_QM_ASSIGN) {
  577. VAR_SOURCE(opline->op1) = NULL;
  578. COPY_NODE(opline->op1, src->op1);
  579. MAKE_NOP(src);
  580. ++(*opt_count);
  581. continue;
  582. }
  583. }
  584. }
  585. break;
  586. }
  587. break;
  588. case ZEND_JMPZNZ:
  589. while (1) {
  590. if (opline->op1_type == IS_CONST) {
  591. ++(*opt_count);
  592. if (zend_is_true(&ZEND_OP1_LITERAL(opline))) {
  593. zend_op *target_opline = ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value);
  594. ZEND_SET_OP_JMP_ADDR(opline, opline->op1, target_opline);
  595. block->successors[0] = block->successors[1];
  596. } else {
  597. zend_op *target_opline = ZEND_OP2_JMP_ADDR(opline);
  598. ZEND_SET_OP_JMP_ADDR(opline, opline->op1, target_opline);
  599. }
  600. block->successors_count = 1;
  601. opline->op1_type = IS_UNUSED;
  602. opline->extended_value = 0;
  603. opline->opcode = ZEND_JMP;
  604. break;
  605. } else if (opline->op1_type == IS_TMP_VAR &&
  606. !zend_bitset_in(used_ext, VAR_NUM(opline->op1.var))) {
  607. src = VAR_SOURCE(opline->op1);
  608. if (src) {
  609. if (src->opcode == ZEND_BOOL_NOT) {
  610. /* T = BOOL_NOT(X) + JMPZNZ(T,L1,L2) -> NOP, JMPZNZ(X,L2,L1) */
  611. uint32_t tmp;
  612. VAR_SOURCE(opline->op1) = NULL;
  613. COPY_NODE(opline->op1, src->op1);
  614. tmp = block->successors[0];
  615. block->successors[0] = block->successors[1];
  616. block->successors[1] = tmp;
  617. MAKE_NOP(src);
  618. ++(*opt_count);
  619. continue;
  620. } else if (src->opcode == ZEND_BOOL ||
  621. src->opcode == ZEND_QM_ASSIGN) {
  622. VAR_SOURCE(opline->op1) = NULL;
  623. COPY_NODE(opline->op1, src->op1);
  624. MAKE_NOP(src);
  625. ++(*opt_count);
  626. continue;
  627. }
  628. }
  629. }
  630. break;
  631. }
  632. break;
  633. case ZEND_JMPZ_EX:
  634. case ZEND_JMPNZ_EX:
  635. while (1) {
  636. if (opline->op1_type == IS_CONST) {
  637. if (zend_is_true(&ZEND_OP1_LITERAL(opline)) ==
  638. (opline->opcode == ZEND_JMPZ_EX)) {
  639. ++(*opt_count);
  640. opline->opcode = ZEND_QM_ASSIGN;
  641. zval_ptr_dtor_nogc(&ZEND_OP1_LITERAL(opline));
  642. ZVAL_BOOL(&ZEND_OP1_LITERAL(opline), opline->opcode == ZEND_JMPZ_EX);
  643. opline->op2.num = 0;
  644. block->successors_count = 1;
  645. block->successors[0] = block->successors[1];
  646. cfg->blocks[block->successors[0]].flags |= ZEND_BB_FOLLOW;
  647. break;
  648. }
  649. } else if (opline->op1_type == IS_TMP_VAR &&
  650. (!zend_bitset_in(used_ext, VAR_NUM(opline->op1.var)) ||
  651. opline->result.var == opline->op1.var)) {
  652. src = VAR_SOURCE(opline->op1);
  653. if (src) {
  654. if (src->opcode == ZEND_BOOL ||
  655. src->opcode == ZEND_QM_ASSIGN) {
  656. VAR_SOURCE(opline->op1) = NULL;
  657. COPY_NODE(opline->op1, src->op1);
  658. MAKE_NOP(src);
  659. ++(*opt_count);
  660. continue;
  661. }
  662. }
  663. }
  664. break;
  665. }
  666. break;
  667. case ZEND_CONCAT:
  668. case ZEND_FAST_CONCAT:
  669. if (opline->op1_type == IS_CONST &&
  670. opline->op2_type == IS_CONST) {
  671. goto optimize_constant_binary_op;
  672. }
  673. if (opline->op2_type == IS_CONST &&
  674. opline->op1_type == IS_TMP_VAR) {
  675. src = VAR_SOURCE(opline->op1);
  676. if (src &&
  677. (src->opcode == ZEND_CONCAT ||
  678. src->opcode == ZEND_FAST_CONCAT) &&
  679. src->op2_type == IS_CONST) {
  680. /* compress consecutive CONCATs */
  681. int l, old_len;
  682. if (Z_TYPE(ZEND_OP2_LITERAL(opline)) != IS_STRING) {
  683. convert_to_string(&ZEND_OP2_LITERAL(opline));
  684. }
  685. if (Z_TYPE(ZEND_OP2_LITERAL(src)) != IS_STRING) {
  686. convert_to_string(&ZEND_OP2_LITERAL(src));
  687. }
  688. VAR_SOURCE(opline->op1) = NULL;
  689. COPY_NODE(opline->op1, src->op1);
  690. old_len = Z_STRLEN(ZEND_OP2_LITERAL(src));
  691. l = old_len + Z_STRLEN(ZEND_OP2_LITERAL(opline));
  692. if (!Z_REFCOUNTED(ZEND_OP2_LITERAL(src))) {
  693. zend_string *tmp = zend_string_alloc(l, 0);
  694. memcpy(ZSTR_VAL(tmp), Z_STRVAL(ZEND_OP2_LITERAL(src)), old_len);
  695. Z_STR(ZEND_OP2_LITERAL(src)) = tmp;
  696. } else {
  697. Z_STR(ZEND_OP2_LITERAL(src)) = zend_string_extend(Z_STR(ZEND_OP2_LITERAL(src)), l, 0);
  698. }
  699. Z_TYPE_INFO(ZEND_OP2_LITERAL(src)) = IS_STRING_EX;
  700. memcpy(Z_STRVAL(ZEND_OP2_LITERAL(src)) + old_len, Z_STRVAL(ZEND_OP2_LITERAL(opline)), Z_STRLEN(ZEND_OP2_LITERAL(opline)));
  701. Z_STRVAL(ZEND_OP2_LITERAL(src))[l] = '\0';
  702. zval_ptr_dtor_str(&ZEND_OP2_LITERAL(opline));
  703. ZVAL_STR(&ZEND_OP2_LITERAL(opline), zend_new_interned_string(Z_STR(ZEND_OP2_LITERAL(src))));
  704. ZVAL_NULL(&ZEND_OP2_LITERAL(src));
  705. MAKE_NOP(src);
  706. ++(*opt_count);
  707. }
  708. }
  709. if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) {
  710. src = VAR_SOURCE(opline->op1);
  711. if (src &&
  712. src->opcode == ZEND_CAST &&
  713. src->extended_value == IS_STRING &&
  714. src->op1_type != IS_CONST) {
  715. /* convert T1 = CAST(STRING, X), T2 = CONCAT(T1, Y) to T2 = CONCAT(X,Y) */
  716. VAR_SOURCE(opline->op1) = NULL;
  717. COPY_NODE(opline->op1, src->op1);
  718. MAKE_NOP(src);
  719. ++(*opt_count);
  720. }
  721. }
  722. if (opline->op2_type & (IS_TMP_VAR|IS_VAR)) {
  723. src = VAR_SOURCE(opline->op2);
  724. if (src &&
  725. src->opcode == ZEND_CAST &&
  726. src->extended_value == IS_STRING &&
  727. src->op1_type != IS_CONST) {
  728. /* convert T1 = CAST(STRING, X), T2 = CONCAT(Y, T1) to T2 = CONCAT(Y,X) */
  729. zend_op *src = VAR_SOURCE(opline->op2);
  730. VAR_SOURCE(opline->op2) = NULL;
  731. COPY_NODE(opline->op2, src->op1);
  732. MAKE_NOP(src);
  733. ++(*opt_count);
  734. }
  735. }
  736. if (opline->op1_type == IS_CONST &&
  737. Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING &&
  738. Z_STRLEN(ZEND_OP1_LITERAL(opline)) == 0) {
  739. /* convert CONCAT('', X) => CAST(STRING, X) */
  740. literal_dtor(&ZEND_OP1_LITERAL(opline));
  741. opline->opcode = ZEND_CAST;
  742. opline->extended_value = IS_STRING;
  743. COPY_NODE(opline->op1, opline->op2);
  744. opline->op2_type = IS_UNUSED;
  745. opline->op2.var = 0;
  746. ++(*opt_count);
  747. } else if (opline->op2_type == IS_CONST &&
  748. Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING &&
  749. Z_STRLEN(ZEND_OP2_LITERAL(opline)) == 0) {
  750. /* convert CONCAT(X, '') => CAST(STRING, X) */
  751. literal_dtor(&ZEND_OP2_LITERAL(opline));
  752. opline->opcode = ZEND_CAST;
  753. opline->extended_value = IS_STRING;
  754. opline->op2_type = IS_UNUSED;
  755. opline->op2.var = 0;
  756. ++(*opt_count);
  757. } else if (opline->opcode == ZEND_CONCAT &&
  758. (opline->op1_type == IS_CONST ||
  759. (opline->op1_type == IS_TMP_VAR &&
  760. VAR_SOURCE(opline->op1) &&
  761. (VAR_SOURCE(opline->op1)->opcode == ZEND_FAST_CONCAT ||
  762. VAR_SOURCE(opline->op1)->opcode == ZEND_ROPE_END ||
  763. VAR_SOURCE(opline->op1)->opcode == ZEND_FETCH_CONSTANT ||
  764. VAR_SOURCE(opline->op1)->opcode == ZEND_FETCH_CLASS_CONSTANT))) &&
  765. (opline->op2_type == IS_CONST ||
  766. (opline->op2_type == IS_TMP_VAR &&
  767. VAR_SOURCE(opline->op2) &&
  768. (VAR_SOURCE(opline->op2)->opcode == ZEND_FAST_CONCAT ||
  769. VAR_SOURCE(opline->op2)->opcode == ZEND_ROPE_END ||
  770. VAR_SOURCE(opline->op2)->opcode == ZEND_FETCH_CONSTANT ||
  771. VAR_SOURCE(opline->op2)->opcode == ZEND_FETCH_CLASS_CONSTANT)))) {
  772. opline->opcode = ZEND_FAST_CONCAT;
  773. ++(*opt_count);
  774. }
  775. break;
  776. case ZEND_ADD:
  777. case ZEND_SUB:
  778. case ZEND_MUL:
  779. case ZEND_DIV:
  780. case ZEND_MOD:
  781. case ZEND_SL:
  782. case ZEND_SR:
  783. case ZEND_IS_SMALLER:
  784. case ZEND_IS_SMALLER_OR_EQUAL:
  785. case ZEND_IS_IDENTICAL:
  786. case ZEND_IS_NOT_IDENTICAL:
  787. case ZEND_BOOL_XOR:
  788. case ZEND_BW_OR:
  789. case ZEND_BW_AND:
  790. case ZEND_BW_XOR:
  791. if (opline->op1_type == IS_CONST &&
  792. opline->op2_type == IS_CONST) {
  793. /* evaluate constant expressions */
  794. zval result;
  795. optimize_constant_binary_op:
  796. if (zend_optimizer_eval_binary_op(&result, opline->opcode, &ZEND_OP1_LITERAL(opline), &ZEND_OP2_LITERAL(opline)) == SUCCESS) {
  797. literal_dtor(&ZEND_OP1_LITERAL(opline));
  798. literal_dtor(&ZEND_OP2_LITERAL(opline));
  799. opline->opcode = ZEND_QM_ASSIGN;
  800. SET_UNUSED(opline->op2);
  801. zend_optimizer_update_op1_const(op_array, opline, &result);
  802. ++(*opt_count);
  803. }
  804. }
  805. break;
  806. case ZEND_BW_NOT:
  807. if (opline->op1_type == IS_CONST) {
  808. /* evaluate constant unary ops */
  809. zval result;
  810. optimize_const_unary_op:
  811. if (zend_optimizer_eval_unary_op(&result, opline->opcode, &ZEND_OP1_LITERAL(opline)) == SUCCESS) {
  812. literal_dtor(&ZEND_OP1_LITERAL(opline));
  813. opline->opcode = ZEND_QM_ASSIGN;
  814. zend_optimizer_update_op1_const(op_array, opline, &result);
  815. ++(*opt_count);
  816. }
  817. }
  818. break;
  819. case ZEND_CAST:
  820. if (opline->op1_type == IS_CONST) {
  821. /* cast of constant operand */
  822. zval result;
  823. if (zend_optimizer_eval_cast(&result, opline->extended_value, &ZEND_OP1_LITERAL(opline)) == SUCCESS) {
  824. literal_dtor(&ZEND_OP1_LITERAL(opline));
  825. opline->opcode = ZEND_QM_ASSIGN;
  826. opline->extended_value = 0;
  827. zend_optimizer_update_op1_const(op_array, opline, &result);
  828. ++(*opt_count);
  829. }
  830. }
  831. break;
  832. case ZEND_STRLEN:
  833. if (opline->op1_type == IS_CONST) {
  834. zval result;
  835. if (zend_optimizer_eval_strlen(&result, &ZEND_OP1_LITERAL(opline)) == SUCCESS) {
  836. literal_dtor(&ZEND_OP1_LITERAL(opline));
  837. opline->opcode = ZEND_QM_ASSIGN;
  838. zend_optimizer_update_op1_const(op_array, opline, &result);
  839. ++(*opt_count);
  840. }
  841. }
  842. break;
  843. case ZEND_RETURN:
  844. case ZEND_EXIT:
  845. if (opline->op1_type == IS_TMP_VAR) {
  846. src = VAR_SOURCE(opline->op1);
  847. if (src && src->opcode == ZEND_QM_ASSIGN) {
  848. zend_op *op = src + 1;
  849. bool optimize = 1;
  850. while (op < opline) {
  851. if ((op->op1_type == opline->op1_type
  852. && op->op1.var == opline->op1.var)
  853. || (op->op2_type == opline->op1_type
  854. && op->op2.var == opline->op1.var)) {
  855. optimize = 0;
  856. break;
  857. }
  858. op++;
  859. }
  860. if (optimize) {
  861. /* T = QM_ASSIGN(X), RETURN(T) to NOP, RETURN(X) */
  862. VAR_SOURCE(opline->op1) = NULL;
  863. COPY_NODE(opline->op1, src->op1);
  864. MAKE_NOP(src);
  865. ++(*opt_count);
  866. }
  867. }
  868. }
  869. break;
  870. case ZEND_QM_ASSIGN:
  871. if (opline->op1_type == opline->result_type &&
  872. opline->op1.var == opline->result.var) {
  873. /* strip T = QM_ASSIGN(T) */
  874. MAKE_NOP(opline);
  875. ++(*opt_count);
  876. } else if (opline->op1_type == IS_TMP_VAR &&
  877. opline->result_type == IS_TMP_VAR &&
  878. !zend_bitset_in(used_ext, VAR_NUM(opline->op1.var))) {
  879. /* T1 = ..., T2 = QM_ASSIGN(T1) to T2 = ..., NOP */
  880. src = VAR_SOURCE(opline->op1);
  881. if (src &&
  882. src->opcode != ZEND_COPY_TMP &&
  883. src->opcode != ZEND_ADD_ARRAY_ELEMENT &&
  884. src->opcode != ZEND_ADD_ARRAY_UNPACK &&
  885. (src->opcode != ZEND_DECLARE_LAMBDA_FUNCTION ||
  886. src == opline -1)) {
  887. src->result.var = opline->result.var;
  888. VAR_SOURCE(opline->op1) = NULL;
  889. VAR_SOURCE(opline->result) = src;
  890. MAKE_NOP(opline);
  891. ++(*opt_count);
  892. }
  893. }
  894. break;
  895. }
  896. /* get variable source */
  897. if (opline->result_type & (IS_VAR|IS_TMP_VAR)) {
  898. SET_VAR_SOURCE(opline);
  899. }
  900. opline++;
  901. }
  902. }
  903. /* Rebuild plain (optimized) op_array from CFG */
  904. static void assemble_code_blocks(zend_cfg *cfg, zend_op_array *op_array, zend_optimizer_ctx *ctx)
  905. {
  906. zend_basic_block *blocks = cfg->blocks;
  907. zend_basic_block *end = blocks + cfg->blocks_count;
  908. zend_basic_block *b;
  909. zend_op *new_opcodes;
  910. zend_op *opline;
  911. uint32_t len = 0;
  912. int n;
  913. for (b = blocks; b < end; b++) {
  914. if (b->len == 0) {
  915. continue;
  916. }
  917. if (b->flags & (ZEND_BB_REACHABLE|ZEND_BB_UNREACHABLE_FREE)) {
  918. opline = op_array->opcodes + b->start + b->len - 1;
  919. if (opline->opcode == ZEND_JMP) {
  920. zend_basic_block *next = b + 1;
  921. while (next < end && !(next->flags & ZEND_BB_REACHABLE)) {
  922. next++;
  923. }
  924. if (next < end && next == blocks + b->successors[0]) {
  925. /* JMP to the next block - strip it */
  926. MAKE_NOP(opline);
  927. b->len--;
  928. }
  929. } else if (b->len == 1 && opline->opcode == ZEND_NOP) {
  930. /* skip empty block */
  931. b->len--;
  932. }
  933. len += b->len;
  934. } else {
  935. /* this block will not be used, delete all constants there */
  936. zend_op *op = op_array->opcodes + b->start;
  937. zend_op *end = op + b->len;
  938. for (; op < end; op++) {
  939. if (op->op1_type == IS_CONST) {
  940. literal_dtor(&ZEND_OP1_LITERAL(op));
  941. }
  942. if (op->op2_type == IS_CONST) {
  943. literal_dtor(&ZEND_OP2_LITERAL(op));
  944. }
  945. }
  946. }
  947. }
  948. new_opcodes = emalloc(len * sizeof(zend_op));
  949. opline = new_opcodes;
  950. /* Copy code of reachable blocks into a single buffer */
  951. for (b = blocks; b < end; b++) {
  952. if (b->flags & (ZEND_BB_REACHABLE|ZEND_BB_UNREACHABLE_FREE)) {
  953. memcpy(opline, op_array->opcodes + b->start, b->len * sizeof(zend_op));
  954. b->start = opline - new_opcodes;
  955. opline += b->len;
  956. }
  957. }
  958. /* adjust jump targets */
  959. efree(op_array->opcodes);
  960. op_array->opcodes = new_opcodes;
  961. op_array->last = len;
  962. for (b = blocks; b < end; b++) {
  963. if (!(b->flags & ZEND_BB_REACHABLE) || b->len == 0) {
  964. continue;
  965. }
  966. opline = op_array->opcodes + b->start + b->len - 1;
  967. switch (opline->opcode) {
  968. case ZEND_FAST_CALL:
  969. case ZEND_JMP:
  970. ZEND_SET_OP_JMP_ADDR(opline, opline->op1, new_opcodes + blocks[b->successors[0]].start);
  971. break;
  972. case ZEND_JMPZNZ:
  973. opline->extended_value = ZEND_OPLINE_TO_OFFSET(opline, new_opcodes + blocks[b->successors[1]].start);
  974. ZEND_FALLTHROUGH;
  975. case ZEND_JMPZ:
  976. case ZEND_JMPNZ:
  977. case ZEND_JMPZ_EX:
  978. case ZEND_JMPNZ_EX:
  979. case ZEND_FE_RESET_R:
  980. case ZEND_FE_RESET_RW:
  981. case ZEND_JMP_SET:
  982. case ZEND_COALESCE:
  983. case ZEND_ASSERT_CHECK:
  984. case ZEND_JMP_NULL:
  985. ZEND_SET_OP_JMP_ADDR(opline, opline->op2, new_opcodes + blocks[b->successors[0]].start);
  986. break;
  987. case ZEND_CATCH:
  988. if (!(opline->extended_value & ZEND_LAST_CATCH)) {
  989. ZEND_SET_OP_JMP_ADDR(opline, opline->op2, new_opcodes + blocks[b->successors[0]].start);
  990. }
  991. break;
  992. case ZEND_FE_FETCH_R:
  993. case ZEND_FE_FETCH_RW:
  994. opline->extended_value = ZEND_OPLINE_TO_OFFSET(opline, new_opcodes + blocks[b->successors[0]].start);
  995. break;
  996. case ZEND_SWITCH_LONG:
  997. case ZEND_SWITCH_STRING:
  998. case ZEND_MATCH:
  999. {
  1000. HashTable *jumptable = Z_ARRVAL(ZEND_OP2_LITERAL(opline));
  1001. zval *zv;
  1002. uint32_t s = 0;
  1003. ZEND_ASSERT(b->successors_count == (opline->opcode == ZEND_MATCH ? 1 : 2) + zend_hash_num_elements(jumptable));
  1004. ZEND_HASH_FOREACH_VAL(jumptable, zv) {
  1005. Z_LVAL_P(zv) = ZEND_OPLINE_TO_OFFSET(opline, new_opcodes + blocks[b->successors[s++]].start);
  1006. } ZEND_HASH_FOREACH_END();
  1007. opline->extended_value = ZEND_OPLINE_TO_OFFSET(opline, new_opcodes + blocks[b->successors[s++]].start);
  1008. break;
  1009. }
  1010. }
  1011. }
  1012. /* adjust exception jump targets & remove unused try_catch_array entries */
  1013. if (op_array->last_try_catch) {
  1014. int i, j;
  1015. uint32_t *map;
  1016. ALLOCA_FLAG(use_heap);
  1017. map = (uint32_t *)do_alloca(sizeof(uint32_t) * op_array->last_try_catch, use_heap);
  1018. for (i = 0, j = 0; i< op_array->last_try_catch; i++) {
  1019. if (blocks[cfg->map[op_array->try_catch_array[i].try_op]].flags & ZEND_BB_REACHABLE) {
  1020. map[i] = j;
  1021. op_array->try_catch_array[j].try_op = blocks[cfg->map[op_array->try_catch_array[i].try_op]].start;
  1022. if (op_array->try_catch_array[i].catch_op) {
  1023. op_array->try_catch_array[j].catch_op = blocks[cfg->map[op_array->try_catch_array[i].catch_op]].start;
  1024. } else {
  1025. op_array->try_catch_array[j].catch_op = 0;
  1026. }
  1027. if (op_array->try_catch_array[i].finally_op) {
  1028. op_array->try_catch_array[j].finally_op = blocks[cfg->map[op_array->try_catch_array[i].finally_op]].start;
  1029. } else {
  1030. op_array->try_catch_array[j].finally_op = 0;
  1031. }
  1032. if (!op_array->try_catch_array[i].finally_end) {
  1033. op_array->try_catch_array[j].finally_end = 0;
  1034. } else {
  1035. op_array->try_catch_array[j].finally_end = blocks[cfg->map[op_array->try_catch_array[i].finally_end]].start;
  1036. }
  1037. j++;
  1038. }
  1039. }
  1040. if (i != j) {
  1041. op_array->last_try_catch = j;
  1042. if (j == 0) {
  1043. efree(op_array->try_catch_array);
  1044. op_array->try_catch_array = NULL;
  1045. }
  1046. if (op_array->fn_flags & ZEND_ACC_HAS_FINALLY_BLOCK) {
  1047. zend_op *opline = new_opcodes;
  1048. zend_op *end = opline + len;
  1049. while (opline < end) {
  1050. if (opline->opcode == ZEND_FAST_RET &&
  1051. opline->op2.num != (uint32_t)-1 &&
  1052. opline->op2.num < (uint32_t)j) {
  1053. opline->op2.num = map[opline->op2.num];
  1054. }
  1055. opline++;
  1056. }
  1057. }
  1058. }
  1059. free_alloca(map, use_heap);
  1060. }
  1061. /* adjust early binding list */
  1062. if (op_array->fn_flags & ZEND_ACC_EARLY_BINDING) {
  1063. ZEND_ASSERT(op_array == &ctx->script->main_op_array);
  1064. ctx->script->first_early_binding_opline =
  1065. zend_build_delayed_early_binding_list(op_array);
  1066. }
  1067. /* rebuild map (just for printing) */
  1068. memset(cfg->map, -1, sizeof(int) * op_array->last);
  1069. for (n = 0; n < cfg->blocks_count; n++) {
  1070. if (cfg->blocks[n].flags & (ZEND_BB_REACHABLE|ZEND_BB_UNREACHABLE_FREE)) {
  1071. cfg->map[cfg->blocks[n].start] = n;
  1072. }
  1073. }
  1074. }
  1075. static zend_always_inline zend_basic_block *get_target_block(const zend_cfg *cfg, zend_basic_block *block, int n, uint32_t *opt_count)
  1076. {
  1077. int b;
  1078. zend_basic_block *target_block = cfg->blocks + block->successors[n];
  1079. if (target_block->len == 0 && !(target_block->flags & ZEND_BB_PROTECTED)) {
  1080. do {
  1081. b = target_block->successors[0];
  1082. target_block = cfg->blocks + b;
  1083. } while (target_block->len == 0 && !(target_block->flags & ZEND_BB_PROTECTED));
  1084. block->successors[n] = b;
  1085. ++(*opt_count);
  1086. }
  1087. return target_block;
  1088. }
  1089. static zend_always_inline zend_basic_block *get_follow_block(const zend_cfg *cfg, zend_basic_block *block, int n, uint32_t *opt_count)
  1090. {
  1091. int b;
  1092. zend_basic_block *target_block = cfg->blocks + block->successors[n];
  1093. if (target_block->len == 0 && !(target_block->flags & ZEND_BB_PROTECTED)) {
  1094. do {
  1095. b = target_block->successors[0];
  1096. target_block = cfg->blocks + b;
  1097. } while (target_block->len == 0 && !(target_block->flags & ZEND_BB_PROTECTED));
  1098. block->successors[n] = b;
  1099. ++(*opt_count);
  1100. }
  1101. return target_block;
  1102. }
  1103. static zend_always_inline zend_basic_block *get_next_block(const zend_cfg *cfg, zend_basic_block *block)
  1104. {
  1105. zend_basic_block *next_block = block + 1;
  1106. zend_basic_block *end = cfg->blocks + cfg->blocks_count;
  1107. while (1) {
  1108. if (next_block == end) {
  1109. return NULL;
  1110. } else if (next_block->flags & ZEND_BB_REACHABLE) {
  1111. break;
  1112. }
  1113. next_block++;
  1114. }
  1115. while (next_block->len == 0 && !(next_block->flags & ZEND_BB_PROTECTED)) {
  1116. next_block = cfg->blocks + next_block->successors[0];
  1117. }
  1118. return next_block;
  1119. }
  1120. /* we use "jmp_hitlist" to avoid infinity loops during jmp optimization */
  1121. static zend_always_inline int in_hitlist(int target, int *jmp_hitlist, int jmp_hitlist_count)
  1122. {
  1123. int i;
  1124. for (i = 0; i < jmp_hitlist_count; i++) {
  1125. if (jmp_hitlist[i] == target) {
  1126. return 1;
  1127. }
  1128. }
  1129. return 0;
  1130. }
  1131. #define CHECK_LOOP(target) \
  1132. if (EXPECTED(!in_hitlist(target, jmp_hitlist, jmp_hitlist_count))) { \
  1133. jmp_hitlist[jmp_hitlist_count++] = target; \
  1134. } else { \
  1135. break; \
  1136. }
  1137. static void zend_jmp_optimization(zend_basic_block *block, zend_op_array *op_array, const zend_cfg *cfg, int *jmp_hitlist, uint32_t *opt_count)
  1138. {
  1139. /* last_op is the last opcode of the current block */
  1140. zend_basic_block *target_block, *follow_block, *next_block;
  1141. zend_op *last_op, *target;
  1142. int next, jmp_hitlist_count;
  1143. if (block->len == 0) {
  1144. return;
  1145. }
  1146. last_op = op_array->opcodes + block->start + block->len - 1;
  1147. switch (last_op->opcode) {
  1148. case ZEND_JMP:
  1149. jmp_hitlist_count = 0;
  1150. target_block = get_target_block(cfg, block, 0, opt_count);
  1151. while (target_block->len == 1) {
  1152. target = op_array->opcodes + target_block->start;
  1153. if (target->opcode == ZEND_JMP) {
  1154. /* JMP L, L: JMP L1 -> JMP L1 */
  1155. next = target_block->successors[0];
  1156. } else {
  1157. break;
  1158. }
  1159. CHECK_LOOP(next);
  1160. block->successors[0] = next;
  1161. ++(*opt_count);
  1162. target_block = get_target_block(cfg, block, 0, opt_count);
  1163. }
  1164. next_block = get_next_block(cfg, block);
  1165. if (target_block == next_block) {
  1166. /* JMP(next) -> NOP */
  1167. MAKE_NOP(last_op);
  1168. ++(*opt_count);
  1169. block->len--;
  1170. } else if (target_block->len == 1) {
  1171. target = op_array->opcodes + target_block->start;
  1172. if (target->opcode == ZEND_JMPZNZ) {
  1173. /* JMP L, L: JMPZNZ L1,L2 -> JMPZNZ L1,L2 */
  1174. *last_op = *target;
  1175. if (last_op->op1_type == IS_CONST) {
  1176. zval zv;
  1177. ZVAL_COPY(&zv, &ZEND_OP1_LITERAL(last_op));
  1178. last_op->op1.constant = zend_optimizer_add_literal(op_array, &zv);
  1179. }
  1180. block->successors_count = 2;
  1181. block->successors[0] = target_block->successors[0];
  1182. block->successors[1] = target_block->successors[1];
  1183. ++(*opt_count);
  1184. goto optimize_jmpznz;
  1185. } else if ((target->opcode == ZEND_RETURN ||
  1186. target->opcode == ZEND_RETURN_BY_REF ||
  1187. target->opcode == ZEND_GENERATOR_RETURN ||
  1188. target->opcode == ZEND_EXIT) &&
  1189. !(op_array->fn_flags & ZEND_ACC_HAS_FINALLY_BLOCK)) {
  1190. /* JMP L, L: RETURN to immediate RETURN */
  1191. *last_op = *target;
  1192. if (last_op->op1_type == IS_CONST) {
  1193. zval zv;
  1194. ZVAL_COPY(&zv, &ZEND_OP1_LITERAL(last_op));
  1195. last_op->op1.constant = zend_optimizer_add_literal(op_array, &zv);
  1196. }
  1197. block->successors_count = 0;
  1198. ++(*opt_count);
  1199. }
  1200. }
  1201. break;
  1202. case ZEND_JMP_SET:
  1203. case ZEND_COALESCE:
  1204. case ZEND_JMP_NULL:
  1205. jmp_hitlist_count = 0;
  1206. target_block = get_target_block(cfg, block, 0, opt_count);
  1207. while (target_block->len == 1) {
  1208. target = op_array->opcodes + target_block->start;
  1209. if (target->opcode == ZEND_JMP) {
  1210. /* JMP_SET(X, L), L: JMP(L2) -> JMP_SET(X, L2) */
  1211. next = target_block->successors[0];
  1212. CHECK_LOOP(next);
  1213. block->successors[0] = next;
  1214. ++(*opt_count);
  1215. } else {
  1216. break;
  1217. }
  1218. target_block = get_target_block(cfg, block, 0, opt_count);
  1219. }
  1220. break;
  1221. case ZEND_JMPZ:
  1222. case ZEND_JMPNZ:
  1223. jmp_hitlist_count = 0;
  1224. target_block = get_target_block(cfg, block, 0, opt_count);
  1225. while (target_block->len == 1) {
  1226. target = op_array->opcodes + target_block->start;
  1227. if (target->opcode == ZEND_JMP) {
  1228. /* JMPZ(X, L), L: JMP(L2) -> JMPZ(X, L2) */
  1229. next = target_block->successors[0];
  1230. } else if (target->opcode == last_op->opcode &&
  1231. SAME_VAR(target->op1, last_op->op1)) {
  1232. /* JMPZ(X, L), L: JMPZ(X, L2) -> JMPZ(X, L2) */
  1233. next = target_block->successors[0];
  1234. } else if (target->opcode == INV_COND(last_op->opcode) &&
  1235. SAME_VAR(target->op1, last_op->op1)) {
  1236. /* JMPZ(X, L), L: JMPNZ(X, L2) -> JMPZ(X, L+1) */
  1237. next = target_block->successors[1];
  1238. } else if (target->opcode == ZEND_JMPZNZ &&
  1239. SAME_VAR(target->op1, last_op->op1)) {
  1240. /* JMPZ(X, L), L: JMPZNZ(X, L2, L3) -> JMPZ(X, L2) */
  1241. next = target_block->successors[last_op->opcode == ZEND_JMPNZ];
  1242. } else {
  1243. break;
  1244. }
  1245. CHECK_LOOP(next);
  1246. block->successors[0] = next;
  1247. ++(*opt_count);
  1248. target_block = get_target_block(cfg, block, 0, opt_count);
  1249. }
  1250. follow_block = get_follow_block(cfg, block, 1, opt_count);
  1251. if (target_block == follow_block) {
  1252. /* L: JMP[N]Z(X, L+1) -> NOP or FREE(X) */
  1253. if (last_op->op1_type == IS_CV) {
  1254. last_op->opcode = ZEND_CHECK_VAR;
  1255. last_op->op2.num = 0;
  1256. } else if (last_op->op1_type & (IS_VAR|IS_TMP_VAR)) {
  1257. last_op->opcode = ZEND_FREE;
  1258. last_op->op2.num = 0;
  1259. } else {
  1260. MAKE_NOP(last_op);
  1261. block->len--;
  1262. }
  1263. block->successors_count = 1;
  1264. ++(*opt_count);
  1265. } else if (follow_block->len == 1) {
  1266. target = op_array->opcodes + follow_block->start;
  1267. if (target->opcode == ZEND_JMP) {
  1268. if (block->successors[0] == follow_block->successors[0]) {
  1269. /* JMPZ(X,L1), JMP(L1) -> NOP, JMP(L1) */
  1270. if (last_op->op1_type == IS_CV) {
  1271. last_op->opcode = ZEND_CHECK_VAR;
  1272. last_op->op2.num = 0;
  1273. } else if (last_op->op1_type & (IS_VAR|IS_TMP_VAR)) {
  1274. last_op->opcode = ZEND_FREE;
  1275. last_op->op2.num = 0;
  1276. } else {
  1277. MAKE_NOP(last_op);
  1278. block->len--;
  1279. }
  1280. block->successors[0] = follow_block - cfg->blocks;
  1281. block->successors_count = 1;
  1282. ++(*opt_count);
  1283. break;
  1284. } else if (!(follow_block->flags & (ZEND_BB_TARGET | ZEND_BB_PROTECTED))) {
  1285. next_block = get_next_block(cfg, follow_block);
  1286. if (target_block == next_block) {
  1287. /* JMPZ(X,L1) JMP(L2) L1: -> JMPNZ(X,L2) NOP*/
  1288. last_op->opcode = INV_COND(last_op->opcode);
  1289. block->successors[0] = follow_block->successors[0];
  1290. block->successors[1] = next_block - cfg->blocks;
  1291. follow_block->flags &= ~ZEND_BB_REACHABLE;
  1292. MAKE_NOP(target);
  1293. follow_block->len = 0;
  1294. next_block->flags |= ZEND_BB_FOLLOW;
  1295. break;
  1296. }
  1297. }
  1298. /* JMPZ(X,L1), JMP(L2) -> JMPZNZ(X,L1,L2) */
  1299. if (last_op->opcode == ZEND_JMPZ) {
  1300. block->successors[1] = follow_block->successors[0];
  1301. } else {
  1302. block->successors[1] = block->successors[0];
  1303. block->successors[0] = follow_block->successors[0];
  1304. }
  1305. last_op->opcode = ZEND_JMPZNZ;
  1306. ++(*opt_count);
  1307. }
  1308. }
  1309. break;
  1310. case ZEND_JMPNZ_EX:
  1311. case ZEND_JMPZ_EX:
  1312. jmp_hitlist_count = 0;
  1313. target_block = get_target_block(cfg, block, 0, opt_count);
  1314. while (target_block->len == 1) {
  1315. target = op_array->opcodes + target_block->start;
  1316. if (target->opcode == ZEND_JMP) {
  1317. /* T = JMPZ_EX(X, L), L: JMP(L2) -> T = JMPZ(X, L2) */
  1318. next = target_block->successors[0];
  1319. } else if (target->opcode == last_op->opcode-3 &&
  1320. (SAME_VAR(target->op1, last_op->result) ||
  1321. SAME_VAR(target->op1, last_op->op1))) {
  1322. /* T = JMPZ_EX(X, L1), L1: JMPZ({X|T}, L2) -> T = JMPZ_EX(X, L2) */
  1323. next = target_block->successors[0];
  1324. } else if (target->opcode == last_op->opcode &&
  1325. target->result.var == last_op->result.var &&
  1326. (SAME_VAR(target->op1, last_op->result) ||
  1327. SAME_VAR(target->op1, last_op->op1))) {
  1328. /* T = JMPZ_EX(X, L1), L1: T = JMPZ_EX({X|T}, L2) -> T = JMPZ_EX(X, L2) */
  1329. next = target_block->successors[0];
  1330. } else if (target->opcode == ZEND_JMPZNZ &&
  1331. (SAME_VAR(target->op1, last_op->result) ||
  1332. SAME_VAR(target->op1, last_op->op1))) {
  1333. /* T = JMPZ_EX(X, L), L: JMPZNZ({X|T}, L2, L3) -> T = JMPZ_EX(X, L2) */
  1334. next = target_block->successors[last_op->opcode == ZEND_JMPNZ_EX];
  1335. } else if (target->opcode == INV_EX_COND(last_op->opcode) &&
  1336. (SAME_VAR(target->op1, last_op->result) ||
  1337. SAME_VAR(target->op1, last_op->op1))) {
  1338. /* T = JMPZ_EX(X, L1), L1: JMPNZ({X|T1}, L2) -> T = JMPZ_EX(X, L1+1) */
  1339. next = target_block->successors[1];
  1340. } else if (target->opcode == INV_EX_COND_EX(last_op->opcode) &&
  1341. target->result.var == last_op->result.var &&
  1342. (SAME_VAR(target->op1, last_op->result) ||
  1343. SAME_VAR(target->op1, last_op->op1))) {
  1344. /* T = JMPZ_EX(X, L1), L1: T = JMPNZ_EX({X|T}, L2) -> T = JMPZ_EX(X, L1+1) */
  1345. next = target_block->successors[1];
  1346. } else if (target->opcode == ZEND_BOOL &&
  1347. (SAME_VAR(target->op1, last_op->result) ||
  1348. SAME_VAR(target->op1, last_op->op1))) {
  1349. /* convert Y = JMPZ_EX(X,L1), L1: Z = BOOL(Y) to
  1350. Z = JMPZ_EX(X,L1+1) */
  1351. /* NOTE: This optimization pattern is not safe, but works, */
  1352. /* because result of JMPZ_EX instruction */
  1353. /* is not used on the following path and */
  1354. /* should be used once on the branch path. */
  1355. /* */
  1356. /* The pattern works well only if jumps processed in */
  1357. /* direct order, otherwise it breaks JMPZ_EX */
  1358. /* sequences too early. */
  1359. last_op->result.var = target->result.var;
  1360. next = target_block->successors[0];
  1361. } else {
  1362. break;
  1363. }
  1364. CHECK_LOOP(next);
  1365. block->successors[0] = next;
  1366. ++(*opt_count);
  1367. target_block = get_target_block(cfg, block, 0, opt_count);
  1368. }
  1369. follow_block = get_follow_block(cfg, block, 1, opt_count);
  1370. if (target_block == follow_block) {
  1371. /* L: T = JMP[N]Z_EX(X, L+1) -> T = BOOL(X) */
  1372. last_op->opcode = ZEND_BOOL;
  1373. last_op->op2.num = 0;
  1374. block->successors_count = 1;
  1375. ++(*opt_count);
  1376. break;
  1377. }
  1378. break;
  1379. case ZEND_JMPZNZ: {
  1380. optimize_jmpznz:
  1381. jmp_hitlist_count = 0;
  1382. target_block = get_target_block(cfg, block, 0, opt_count);
  1383. while (target_block->len == 1) {
  1384. target = op_array->opcodes + target_block->start;
  1385. if (target->opcode == ZEND_JMP) {
  1386. /* JMPZNZ(X, L1, L2), L1: JMP(L3) -> JMPZNZ(X, L3, L2) */
  1387. next = target_block->successors[0];
  1388. } else if ((target->opcode == ZEND_JMPZ || target->opcode == ZEND_JMPZNZ) &&
  1389. SAME_VAR(target->op1, last_op->op1)) {
  1390. /* JMPZNZ(X, L1, L2), L1: JMPZ(X, L3) -> JMPZNZ(X, L3, L2) */
  1391. next = target_block->successors[0];
  1392. } else if (target->opcode == ZEND_JMPNZ &&
  1393. SAME_VAR(target->op1, last_op->op1)) {
  1394. /* JMPZNZ(X, L1, L2), L1: X = JMPNZ(X, L3) -> JMPZNZ(X, L1+1, L2) */
  1395. next = target_block->successors[1];
  1396. } else {
  1397. break;
  1398. }
  1399. CHECK_LOOP(next);
  1400. block->successors[0] = next;
  1401. ++(*opt_count);
  1402. target_block = get_target_block(cfg, block, 0, opt_count);
  1403. }
  1404. jmp_hitlist_count = 0;
  1405. follow_block = get_target_block(cfg, block, 1, opt_count);
  1406. while (follow_block->len == 1) {
  1407. target = op_array->opcodes + follow_block->start;
  1408. if (target->opcode == ZEND_JMP) {
  1409. /* JMPZNZ(X, L1, L2), L2: JMP(L3) -> JMPZNZ(X, L1, L3) */
  1410. next = follow_block->successors[0];
  1411. } else if (target->opcode == ZEND_JMPNZ &&
  1412. SAME_VAR(target->op1, last_op->op1)) {
  1413. /* JMPZNZ(X, L1, L2), L2: X = JMPNZ(X, L3) -> JMPZNZ(X, L1, L3) */
  1414. next = follow_block->successors[0];
  1415. } else if ((target->opcode == ZEND_JMPZ || target->opcode == ZEND_JMPZNZ) &&
  1416. SAME_VAR(target->op1, last_op->op1)) {
  1417. /* JMPZNZ(X, L1, L2), L2: JMPZ(X, L3) -> JMPZNZ(X, L1, L2+1) */
  1418. next = follow_block->successors[1];
  1419. } else {
  1420. break;
  1421. }
  1422. CHECK_LOOP(next);
  1423. block->successors[1] = next;
  1424. ++(*opt_count);
  1425. follow_block = get_target_block(cfg, block, 1, opt_count);
  1426. }
  1427. next_block = get_next_block(cfg, block);
  1428. if (target_block == follow_block &&
  1429. !(last_op->op1_type & (IS_VAR|IS_TMP_VAR))) {
  1430. /* JMPZNZ(?,L,L) -> JMP(L) */
  1431. last_op->opcode = ZEND_JMP;
  1432. SET_UNUSED(last_op->op1);
  1433. SET_UNUSED(last_op->op2);
  1434. last_op->extended_value = 0;
  1435. block->successors_count = 1;
  1436. ++(*opt_count);
  1437. } else if (target_block == next_block) {
  1438. /* jumping to next on Z - can follow to it and jump only on NZ */
  1439. /* JMPZNZ(X,L1,L2) L1: -> JMPNZ(X,L2) */
  1440. int tmp = block->successors[0];
  1441. last_op->opcode = ZEND_JMPNZ;
  1442. block->successors[0] = block->successors[1];
  1443. block->successors[1] = tmp;
  1444. ++(*opt_count);
  1445. } else if (follow_block == next_block) {
  1446. /* jumping to next on NZ - can follow to it and jump only on Z */
  1447. /* JMPZNZ(X,L1,L2) L2: -> JMPZ(X,L1) */
  1448. last_op->opcode = ZEND_JMPZ;
  1449. ++(*opt_count);
  1450. }
  1451. break;
  1452. }
  1453. }
  1454. }
  1455. /* Global data dependencies */
  1456. /* Find a set of variables which are used outside of the block where they are
  1457. * defined. We won't apply some optimization patterns for such variables. */
  1458. static void zend_t_usage(zend_cfg *cfg, zend_op_array *op_array, zend_bitset used_ext, zend_optimizer_ctx *ctx)
  1459. {
  1460. int n;
  1461. zend_basic_block *block, *next_block;
  1462. uint32_t var_num;
  1463. uint32_t bitset_len;
  1464. zend_bitset usage;
  1465. zend_bitset defined_here;
  1466. void *checkpoint;
  1467. zend_op *opline, *end;
  1468. if (op_array->T == 0) {
  1469. /* shortcut - if no Ts, nothing to do */
  1470. return;
  1471. }
  1472. checkpoint = zend_arena_checkpoint(ctx->arena);
  1473. bitset_len = zend_bitset_len(op_array->last_var + op_array->T);
  1474. defined_here = zend_arena_alloc(&ctx->arena, bitset_len * ZEND_BITSET_ELM_SIZE);
  1475. zend_bitset_clear(defined_here, bitset_len);
  1476. for (n = 1; n < cfg->blocks_count; n++) {
  1477. block = cfg->blocks + n;
  1478. if (!(block->flags & ZEND_BB_REACHABLE)) {
  1479. continue;
  1480. }
  1481. opline = op_array->opcodes + block->start;
  1482. end = opline + block->len;
  1483. if (!(block->flags & ZEND_BB_FOLLOW) ||
  1484. (block->flags & ZEND_BB_TARGET)) {
  1485. /* Skip continuation of "extended" BB */
  1486. zend_bitset_clear(defined_here, bitset_len);
  1487. }
  1488. while (opline<end) {
  1489. if (opline->op1_type & (IS_VAR|IS_TMP_VAR)) {
  1490. var_num = VAR_NUM(opline->op1.var);
  1491. if (!zend_bitset_in(defined_here, var_num)) {
  1492. zend_bitset_incl(used_ext, var_num);
  1493. }
  1494. }
  1495. if (opline->op2_type == IS_VAR) {
  1496. var_num = VAR_NUM(opline->op2.var);
  1497. if (opline->opcode == ZEND_FE_FETCH_R ||
  1498. opline->opcode == ZEND_FE_FETCH_RW) {
  1499. /* these opcode use the op2 as result */
  1500. zend_bitset_incl(defined_here, var_num);
  1501. } else if (!zend_bitset_in(defined_here, var_num)) {
  1502. zend_bitset_incl(used_ext, var_num);
  1503. }
  1504. } else if (opline->op2_type == IS_TMP_VAR) {
  1505. var_num = VAR_NUM(opline->op2.var);
  1506. if (!zend_bitset_in(defined_here, var_num)) {
  1507. zend_bitset_incl(used_ext, var_num);
  1508. }
  1509. }
  1510. if (opline->result_type == IS_VAR) {
  1511. var_num = VAR_NUM(opline->result.var);
  1512. zend_bitset_incl(defined_here, var_num);
  1513. } else if (opline->result_type == IS_TMP_VAR) {
  1514. var_num = VAR_NUM(opline->result.var);
  1515. switch (opline->opcode) {
  1516. case ZEND_ADD_ARRAY_ELEMENT:
  1517. case ZEND_ADD_ARRAY_UNPACK:
  1518. case ZEND_ROPE_ADD:
  1519. /* these opcodes use the result as argument */
  1520. if (!zend_bitset_in(defined_here, var_num)) {
  1521. zend_bitset_incl(used_ext, var_num);
  1522. }
  1523. break;
  1524. default :
  1525. zend_bitset_incl(defined_here, var_num);
  1526. }
  1527. }
  1528. opline++;
  1529. }
  1530. }
  1531. if (ctx->debug_level & ZEND_DUMP_BLOCK_PASS_VARS) {
  1532. int printed = 0;
  1533. uint32_t i;
  1534. for (i = op_array->last_var; i< op_array->T; i++) {
  1535. if (zend_bitset_in(used_ext, i)) {
  1536. if (!printed) {
  1537. fprintf(stderr, "NON-LOCAL-VARS: %d", i);
  1538. printed = 1;
  1539. } else {
  1540. fprintf(stderr, ", %d", i);
  1541. }
  1542. }
  1543. }
  1544. if (printed) {
  1545. fprintf(stderr, "\n");
  1546. }
  1547. }
  1548. usage = defined_here;
  1549. next_block = NULL;
  1550. for (n = cfg->blocks_count; n > 0;) {
  1551. block = cfg->blocks + (--n);
  1552. if (!(block->flags & ZEND_BB_REACHABLE) || block->len == 0) {
  1553. continue;
  1554. }
  1555. end = op_array->opcodes + block->start;
  1556. opline = end + block->len - 1;
  1557. if (!next_block ||
  1558. !(next_block->flags & ZEND_BB_FOLLOW) ||
  1559. (next_block->flags & ZEND_BB_TARGET)) {
  1560. /* Skip continuation of "extended" BB */
  1561. zend_bitset_copy(usage, used_ext, bitset_len);
  1562. } else if (block->successors_count > 1) {
  1563. zend_bitset_union(usage, used_ext, bitset_len);
  1564. }
  1565. next_block = block;
  1566. while (opline >= end) {
  1567. /* usage checks */
  1568. if (opline->result_type & (IS_VAR|IS_TMP_VAR)) {
  1569. if (!zend_bitset_in(usage, VAR_NUM(opline->result.var))) {
  1570. switch (opline->opcode) {
  1571. case ZEND_ASSIGN_OP:
  1572. case ZEND_ASSIGN_DIM_OP:
  1573. case ZEND_ASSIGN_OBJ_OP:
  1574. case ZEND_ASSIGN_STATIC_PROP_OP:
  1575. case ZEND_PRE_INC:
  1576. case ZEND_PRE_DEC:
  1577. case ZEND_ASSIGN:
  1578. case ZEND_ASSIGN_REF:
  1579. case ZEND_DO_FCALL:
  1580. case ZEND_DO_ICALL:
  1581. case ZEND_DO_UCALL:
  1582. case ZEND_DO_FCALL_BY_NAME:
  1583. opline->result_type = IS_UNUSED;
  1584. break;
  1585. case ZEND_POST_INC:
  1586. case ZEND_POST_DEC:
  1587. case ZEND_POST_INC_OBJ:
  1588. case ZEND_POST_DEC_OBJ:
  1589. case ZEND_POST_INC_STATIC_PROP:
  1590. case ZEND_POST_DEC_STATIC_PROP:
  1591. opline->opcode -= 2;
  1592. opline->result_type = IS_UNUSED;
  1593. break;
  1594. case ZEND_QM_ASSIGN:
  1595. case ZEND_BOOL:
  1596. case ZEND_BOOL_NOT:
  1597. if (opline->op1_type == IS_CV) {
  1598. opline->opcode = ZEND_CHECK_VAR;
  1599. SET_UNUSED(opline->result);
  1600. } else if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) {
  1601. opline->opcode = ZEND_FREE;
  1602. SET_UNUSED(opline->result);
  1603. } else {
  1604. if (opline->op1_type == IS_CONST) {
  1605. literal_dtor(&ZEND_OP1_LITERAL(opline));
  1606. }
  1607. MAKE_NOP(opline);
  1608. }
  1609. break;
  1610. case ZEND_JMPZ_EX:
  1611. case ZEND_JMPNZ_EX:
  1612. opline->opcode -= 3;
  1613. SET_UNUSED(opline->result);
  1614. break;
  1615. case ZEND_ADD_ARRAY_ELEMENT:
  1616. case ZEND_ADD_ARRAY_UNPACK:
  1617. case ZEND_ROPE_ADD:
  1618. zend_bitset_incl(usage, VAR_NUM(opline->result.var));
  1619. break;
  1620. }
  1621. } else {
  1622. switch (opline->opcode) {
  1623. case ZEND_ADD_ARRAY_ELEMENT:
  1624. case ZEND_ADD_ARRAY_UNPACK:
  1625. case ZEND_ROPE_ADD:
  1626. break;
  1627. default:
  1628. zend_bitset_excl(usage, VAR_NUM(opline->result.var));
  1629. break;
  1630. }
  1631. }
  1632. }
  1633. if (opline->op2_type == IS_VAR) {
  1634. switch (opline->opcode) {
  1635. case ZEND_FE_FETCH_R:
  1636. case ZEND_FE_FETCH_RW:
  1637. zend_bitset_excl(usage, VAR_NUM(opline->op2.var));
  1638. break;
  1639. default:
  1640. zend_bitset_incl(usage, VAR_NUM(opline->op2.var));
  1641. break;
  1642. }
  1643. } else if (opline->op2_type == IS_TMP_VAR) {
  1644. zend_bitset_incl(usage, VAR_NUM(opline->op2.var));
  1645. }
  1646. if (opline->op1_type & (IS_VAR|IS_TMP_VAR)) {
  1647. zend_bitset_incl(usage, VAR_NUM(opline->op1.var));
  1648. }
  1649. opline--;
  1650. }
  1651. }
  1652. zend_arena_release(&ctx->arena, checkpoint);
  1653. }
  1654. static void zend_merge_blocks(zend_op_array *op_array, zend_cfg *cfg, uint32_t *opt_count)
  1655. {
  1656. int i;
  1657. zend_basic_block *b, *bb;
  1658. zend_basic_block *prev = NULL;
  1659. for (i = 0; i < cfg->blocks_count; i++) {
  1660. b = cfg->blocks + i;
  1661. if (b->flags & ZEND_BB_REACHABLE) {
  1662. if ((b->flags & ZEND_BB_FOLLOW) &&
  1663. !(b->flags & (ZEND_BB_TARGET | ZEND_BB_PROTECTED)) &&
  1664. prev && prev->successors_count == 1 && prev->successors[0] == i)
  1665. {
  1666. zend_op *last_op = op_array->opcodes + prev->start + prev->len - 1;
  1667. if (prev->len != 0 && last_op->opcode == ZEND_JMP) {
  1668. MAKE_NOP(last_op);
  1669. }
  1670. for (bb = prev + 1; bb != b; bb++) {
  1671. zend_op *op = op_array->opcodes + bb->start;
  1672. zend_op *end = op + bb->len;
  1673. while (op < end) {
  1674. if (op->op1_type == IS_CONST) {
  1675. literal_dtor(&ZEND_OP1_LITERAL(op));
  1676. }
  1677. if (op->op2_type == IS_CONST) {
  1678. literal_dtor(&ZEND_OP2_LITERAL(op));
  1679. }
  1680. MAKE_NOP(op);
  1681. op++;
  1682. }
  1683. /* make block empty */
  1684. bb->len = 0;
  1685. }
  1686. /* re-link */
  1687. prev->flags |= (b->flags & ZEND_BB_EXIT);
  1688. prev->len = b->start + b->len - prev->start;
  1689. prev->successors_count = b->successors_count;
  1690. if (b->successors != b->successors_storage) {
  1691. prev->successors = b->successors;
  1692. b->successors = b->successors_storage;
  1693. } else {
  1694. memcpy(prev->successors, b->successors, b->successors_count * sizeof(int));
  1695. }
  1696. /* unlink & make block empty and unreachable */
  1697. b->flags = 0;
  1698. b->len = 0;
  1699. b->successors_count = 0;
  1700. ++(*opt_count);
  1701. } else {
  1702. prev = b;
  1703. }
  1704. }
  1705. }
  1706. }
  1707. #define PASSES 3
  1708. void zend_optimize_cfg(zend_op_array *op_array, zend_optimizer_ctx *ctx)
  1709. {
  1710. zend_cfg cfg;
  1711. zend_basic_block *blocks, *end, *b;
  1712. int pass;
  1713. uint32_t bitset_len;
  1714. zend_bitset usage;
  1715. void *checkpoint;
  1716. zend_op **Tsource;
  1717. uint32_t opt_count;
  1718. int *jmp_hitlist;
  1719. /* Build CFG */
  1720. checkpoint = zend_arena_checkpoint(ctx->arena);
  1721. if (zend_build_cfg(&ctx->arena, op_array, 0, &cfg) != SUCCESS) {
  1722. zend_arena_release(&ctx->arena, checkpoint);
  1723. return;
  1724. }
  1725. if (cfg.blocks_count * (op_array->last_var + op_array->T) > 64 * 1024 * 1024) {
  1726. zend_arena_release(&ctx->arena, checkpoint);
  1727. return;
  1728. }
  1729. if (ctx->debug_level & ZEND_DUMP_BEFORE_BLOCK_PASS) {
  1730. zend_dump_op_array(op_array, ZEND_DUMP_CFG, "before block pass", &cfg);
  1731. }
  1732. bitset_len = zend_bitset_len(op_array->last_var + op_array->T);
  1733. Tsource = zend_arena_calloc(&ctx->arena, op_array->last_var + op_array->T, sizeof(zend_op *));
  1734. usage = zend_arena_alloc(&ctx->arena, bitset_len * ZEND_BITSET_ELM_SIZE);
  1735. jmp_hitlist = zend_arena_alloc(&ctx->arena, cfg.blocks_count * sizeof(int));
  1736. blocks = cfg.blocks;
  1737. end = blocks + cfg.blocks_count;
  1738. for (pass = 0; pass < PASSES; pass++) {
  1739. opt_count = 0;
  1740. /* Compute data dependencies */
  1741. zend_bitset_clear(usage, bitset_len);
  1742. zend_t_usage(&cfg, op_array, usage, ctx);
  1743. /* optimize each basic block separately */
  1744. for (b = blocks; b < end; b++) {
  1745. if (!(b->flags & ZEND_BB_REACHABLE)) {
  1746. continue;
  1747. }
  1748. /* we track data dependencies only inside a single basic block */
  1749. if (!(b->flags & ZEND_BB_FOLLOW) ||
  1750. (b->flags & ZEND_BB_TARGET)) {
  1751. /* Skip continuation of "extended" BB */
  1752. memset(Tsource, 0, (op_array->last_var + op_array->T) * sizeof(zend_op *));
  1753. }
  1754. zend_optimize_block(b, op_array, usage, &cfg, Tsource, &opt_count);
  1755. }
  1756. /* Eliminate NOPs */
  1757. for (b = blocks; b < end; b++) {
  1758. if (b->flags & ZEND_BB_UNREACHABLE_FREE) {
  1759. /* In unreachable_free blocks only preserve loop var frees. */
  1760. for (uint32_t i = b->start; i < b->start + b->len; i++) {
  1761. zend_op *opline = &op_array->opcodes[i];
  1762. if (!zend_optimizer_is_loop_var_free(opline)) {
  1763. MAKE_NOP(opline);
  1764. }
  1765. }
  1766. }
  1767. if (b->flags & (ZEND_BB_REACHABLE|ZEND_BB_UNREACHABLE_FREE)) {
  1768. strip_nops(op_array, b);
  1769. }
  1770. }
  1771. opt_count = 0;
  1772. /* Jump optimization for each block */
  1773. for (b = blocks; b < end; b++) {
  1774. if (b->flags & ZEND_BB_REACHABLE) {
  1775. zend_jmp_optimization(b, op_array, &cfg, jmp_hitlist, &opt_count);
  1776. }
  1777. }
  1778. /* Eliminate unreachable basic blocks */
  1779. zend_cfg_remark_reachable_blocks(op_array, &cfg);
  1780. /* Merge Blocks */
  1781. zend_merge_blocks(op_array, &cfg, &opt_count);
  1782. if (opt_count == 0) {
  1783. break;
  1784. }
  1785. }
  1786. assemble_code_blocks(&cfg, op_array, ctx);
  1787. if (ctx->debug_level & ZEND_DUMP_AFTER_BLOCK_PASS) {
  1788. zend_dump_op_array(op_array, ZEND_DUMP_CFG | ZEND_DUMP_HIDE_UNREACHABLE, "after block pass", &cfg);
  1789. }
  1790. /* Destroy CFG */
  1791. zend_arena_release(&ctx->arena, checkpoint);
  1792. }