pass1.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657
  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. /* pass 1 (Simple local optimizations)
  22. * - persistent constant substitution (true, false, null, etc)
  23. * - constant casting (ADD expects numbers, CONCAT strings, etc)
  24. * - constant expression evaluation
  25. * - optimize constant conditional JMPs
  26. * - pre-evaluate constant function calls
  27. * - eliminate FETCH $GLOBALS followed by FETCH_DIM/UNSET_DIM/ISSET_ISEMPTY_DIM
  28. */
  29. #include "php.h"
  30. #include "Optimizer/zend_optimizer.h"
  31. #include "Optimizer/zend_optimizer_internal.h"
  32. #include "zend_API.h"
  33. #include "zend_constants.h"
  34. #include "zend_execute.h"
  35. #include "zend_vm.h"
  36. void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx)
  37. {
  38. zend_op *opline = op_array->opcodes;
  39. zend_op *end = opline + op_array->last;
  40. bool collect_constants = (ZEND_OPTIMIZER_PASS_15 & ctx->optimization_level)?
  41. (op_array == &ctx->script->main_op_array) : 0;
  42. while (opline < end) {
  43. switch (opline->opcode) {
  44. case ZEND_CONCAT:
  45. case ZEND_FAST_CONCAT:
  46. if (opline->op1_type == IS_CONST) {
  47. if (Z_TYPE(ZEND_OP1_LITERAL(opline)) != IS_STRING) {
  48. convert_to_string(&ZEND_OP1_LITERAL(opline));
  49. }
  50. }
  51. if (opline->op2_type == IS_CONST) {
  52. if (Z_TYPE(ZEND_OP2_LITERAL(opline)) != IS_STRING) {
  53. convert_to_string(&ZEND_OP2_LITERAL(opline));
  54. }
  55. if (opline->op1_type == IS_CONST) {
  56. goto constant_binary_op;
  57. }
  58. }
  59. break;
  60. case ZEND_ADD:
  61. case ZEND_SUB:
  62. case ZEND_MUL:
  63. case ZEND_DIV:
  64. case ZEND_POW:
  65. case ZEND_MOD:
  66. case ZEND_SL:
  67. case ZEND_SR:
  68. case ZEND_BW_OR:
  69. case ZEND_BW_AND:
  70. case ZEND_BW_XOR:
  71. case ZEND_IS_EQUAL:
  72. case ZEND_IS_NOT_EQUAL:
  73. case ZEND_IS_SMALLER:
  74. case ZEND_IS_SMALLER_OR_EQUAL:
  75. case ZEND_IS_IDENTICAL:
  76. case ZEND_IS_NOT_IDENTICAL:
  77. case ZEND_BOOL_XOR:
  78. case ZEND_SPACESHIP:
  79. case ZEND_CASE:
  80. case ZEND_CASE_STRICT:
  81. if (opline->op1_type == IS_CONST &&
  82. opline->op2_type == IS_CONST) {
  83. /* binary operation with constant operands */
  84. zval result;
  85. constant_binary_op:
  86. if (zend_optimizer_eval_binary_op(&result, opline->opcode, &ZEND_OP1_LITERAL(opline), &ZEND_OP2_LITERAL(opline)) == SUCCESS) {
  87. literal_dtor(&ZEND_OP1_LITERAL(opline));
  88. literal_dtor(&ZEND_OP2_LITERAL(opline));
  89. if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_TMP_VAR, opline->result.var, &result)) {
  90. MAKE_NOP(opline);
  91. } else {
  92. opline->opcode = ZEND_QM_ASSIGN;
  93. SET_UNUSED(opline->op2);
  94. zend_optimizer_update_op1_const(op_array, opline, &result);
  95. }
  96. }
  97. }
  98. break;
  99. case ZEND_ASSIGN_OP:
  100. if (opline->extended_value == ZEND_CONCAT && opline->op2_type == IS_CONST
  101. && Z_TYPE(ZEND_OP2_LITERAL(opline)) != IS_STRING) {
  102. convert_to_string(&ZEND_OP2_LITERAL(opline));
  103. }
  104. break;
  105. case ZEND_CAST:
  106. if (opline->op1_type == IS_CONST) {
  107. /* cast of constant operand */
  108. zval result;
  109. if (zend_optimizer_eval_cast(&result, opline->extended_value, &ZEND_OP1_LITERAL(opline)) == SUCCESS) {
  110. literal_dtor(&ZEND_OP1_LITERAL(opline));
  111. if (zend_optimizer_replace_by_const(op_array, opline + 1, opline->result_type, opline->result.var, &result)) {
  112. MAKE_NOP(opline);
  113. } else {
  114. opline->opcode = ZEND_QM_ASSIGN;
  115. opline->extended_value = 0;
  116. zend_optimizer_update_op1_const(op_array, opline, &result);
  117. }
  118. break;
  119. }
  120. }
  121. break;
  122. case ZEND_BW_NOT:
  123. case ZEND_BOOL_NOT:
  124. if (opline->op1_type == IS_CONST) {
  125. /* unary operation on constant operand */
  126. zval result;
  127. if (zend_optimizer_eval_unary_op(&result, opline->opcode, &ZEND_OP1_LITERAL(opline)) == SUCCESS) {
  128. literal_dtor(&ZEND_OP1_LITERAL(opline));
  129. if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_TMP_VAR, opline->result.var, &result)) {
  130. MAKE_NOP(opline);
  131. } else {
  132. opline->opcode = ZEND_QM_ASSIGN;
  133. zend_optimizer_update_op1_const(op_array, opline, &result);
  134. }
  135. }
  136. }
  137. break;
  138. case ZEND_FETCH_CONSTANT:
  139. if (opline->op2_type == IS_CONST &&
  140. Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING &&
  141. Z_STRLEN(ZEND_OP2_LITERAL(opline)) == sizeof("__COMPILER_HALT_OFFSET__") - 1 &&
  142. memcmp(Z_STRVAL(ZEND_OP2_LITERAL(opline)), "__COMPILER_HALT_OFFSET__", sizeof("__COMPILER_HALT_OFFSET__") - 1) == 0) {
  143. /* substitute __COMPILER_HALT_OFFSET__ constant */
  144. zend_execute_data *orig_execute_data = EG(current_execute_data);
  145. zend_execute_data fake_execute_data;
  146. zval *offset;
  147. memset(&fake_execute_data, 0, sizeof(zend_execute_data));
  148. fake_execute_data.func = (zend_function*)op_array;
  149. EG(current_execute_data) = &fake_execute_data;
  150. if ((offset = zend_get_constant_str("__COMPILER_HALT_OFFSET__", sizeof("__COMPILER_HALT_OFFSET__") - 1)) != NULL) {
  151. literal_dtor(&ZEND_OP2_LITERAL(opline));
  152. if (zend_optimizer_replace_by_const(op_array, opline, IS_TMP_VAR, opline->result.var, offset)) {
  153. MAKE_NOP(opline);
  154. } else {
  155. opline->opcode = ZEND_QM_ASSIGN;
  156. opline->extended_value = 0;
  157. SET_UNUSED(opline->op2);
  158. zend_optimizer_update_op1_const(op_array, opline, offset);
  159. }
  160. }
  161. EG(current_execute_data) = orig_execute_data;
  162. break;
  163. }
  164. if (opline->op2_type == IS_CONST &&
  165. Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING) {
  166. /* substitute persistent constants */
  167. zval c;
  168. if (!zend_optimizer_get_persistent_constant(Z_STR(ZEND_OP2_LITERAL(opline)), &c, 1)) {
  169. if (!ctx->constants || !zend_optimizer_get_collected_constant(ctx->constants, &ZEND_OP2_LITERAL(opline), &c)) {
  170. break;
  171. }
  172. }
  173. if (Z_TYPE(c) == IS_CONSTANT_AST) {
  174. break;
  175. }
  176. literal_dtor(&ZEND_OP2_LITERAL(opline));
  177. if (zend_optimizer_replace_by_const(op_array, opline, IS_TMP_VAR, opline->result.var, &c)) {
  178. MAKE_NOP(opline);
  179. } else {
  180. opline->opcode = ZEND_QM_ASSIGN;
  181. opline->extended_value = 0;
  182. SET_UNUSED(opline->op2);
  183. zend_optimizer_update_op1_const(op_array, opline, &c);
  184. }
  185. }
  186. break;
  187. case ZEND_FETCH_CLASS_CONSTANT:
  188. if (opline->op2_type == IS_CONST &&
  189. Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING) {
  190. zend_class_entry *ce = NULL;
  191. if (opline->op1_type == IS_CONST &&
  192. Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING) {
  193. /* for A::B */
  194. if (op_array->scope &&
  195. zend_string_equals_ci(Z_STR(ZEND_OP1_LITERAL(opline)), op_array->scope->name)) {
  196. ce = op_array->scope;
  197. } else {
  198. ce = zend_optimizer_get_class_entry(
  199. ctx->script, Z_STR(op_array->literals[opline->op1.constant + 1]));
  200. if (!ce) {
  201. break;
  202. }
  203. }
  204. } else if (op_array->scope &&
  205. opline->op1_type == IS_UNUSED &&
  206. (opline->op1.num & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_SELF) {
  207. /* for self::B */
  208. ce = op_array->scope;
  209. } else if (op_array->scope &&
  210. opline->op1_type == IS_VAR &&
  211. (opline - 1)->opcode == ZEND_FETCH_CLASS &&
  212. ((opline - 1)->op2_type == IS_UNUSED &&
  213. ((opline - 1)->op1.num & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_SELF) &&
  214. (opline - 1)->result.var == opline->op1.var) {
  215. /* for self::B */
  216. ce = op_array->scope;
  217. }
  218. if (ce) {
  219. zend_class_constant *cc;
  220. zval *c, t;
  221. if ((cc = zend_hash_find_ptr(&ce->constants_table,
  222. Z_STR(ZEND_OP2_LITERAL(opline)))) != NULL &&
  223. (ZEND_CLASS_CONST_FLAGS(cc) & ZEND_ACC_PPP_MASK) == ZEND_ACC_PUBLIC) {
  224. c = &cc->value;
  225. if (Z_TYPE_P(c) == IS_CONSTANT_AST) {
  226. zend_ast *ast = Z_ASTVAL_P(c);
  227. if (ast->kind != ZEND_AST_CONSTANT
  228. || !zend_optimizer_get_persistent_constant(zend_ast_get_constant_name(ast), &t, 1)
  229. || Z_TYPE(t) == IS_CONSTANT_AST) {
  230. break;
  231. }
  232. } else {
  233. ZVAL_COPY_OR_DUP(&t, c);
  234. }
  235. if (opline->op1_type == IS_CONST) {
  236. literal_dtor(&ZEND_OP1_LITERAL(opline));
  237. } else if (opline->op1_type == IS_VAR) {
  238. MAKE_NOP((opline - 1));
  239. }
  240. literal_dtor(&ZEND_OP2_LITERAL(opline));
  241. if (zend_optimizer_replace_by_const(op_array, opline, IS_TMP_VAR, opline->result.var, &t)) {
  242. MAKE_NOP(opline);
  243. } else {
  244. opline->opcode = ZEND_QM_ASSIGN;
  245. opline->extended_value = 0;
  246. SET_UNUSED(opline->op2);
  247. zend_optimizer_update_op1_const(op_array, opline, &t);
  248. }
  249. }
  250. }
  251. }
  252. break;
  253. case ZEND_DO_ICALL: {
  254. zend_op *send1_opline = opline - 1;
  255. zend_op *send2_opline = NULL;
  256. zend_op *init_opline = NULL;
  257. while (send1_opline->opcode == ZEND_NOP) {
  258. send1_opline--;
  259. }
  260. if (send1_opline->opcode != ZEND_SEND_VAL ||
  261. send1_opline->op1_type != IS_CONST) {
  262. /* don't collect constants after unknown function call */
  263. collect_constants = 0;
  264. break;
  265. }
  266. if (send1_opline->op2.num == 2) {
  267. send2_opline = send1_opline;
  268. send1_opline--;
  269. while (send1_opline->opcode == ZEND_NOP) {
  270. send1_opline--;
  271. }
  272. if (send1_opline->opcode != ZEND_SEND_VAL ||
  273. send1_opline->op1_type != IS_CONST) {
  274. /* don't collect constants after unknown function call */
  275. collect_constants = 0;
  276. break;
  277. }
  278. }
  279. init_opline = send1_opline - 1;
  280. while (init_opline->opcode == ZEND_NOP) {
  281. init_opline--;
  282. }
  283. if (init_opline->opcode != ZEND_INIT_FCALL ||
  284. init_opline->op2_type != IS_CONST ||
  285. Z_TYPE(ZEND_OP2_LITERAL(init_opline)) != IS_STRING) {
  286. /* don't collect constants after unknown function call */
  287. collect_constants = 0;
  288. break;
  289. }
  290. /* define("name", scalar); */
  291. if (zend_string_equals_literal_ci(Z_STR(ZEND_OP2_LITERAL(init_opline)), "define")) {
  292. if (Z_TYPE(ZEND_OP1_LITERAL(send1_opline)) == IS_STRING &&
  293. send2_opline &&
  294. Z_TYPE(ZEND_OP1_LITERAL(send2_opline)) <= IS_STRING) {
  295. if (collect_constants) {
  296. zend_optimizer_collect_constant(ctx, &ZEND_OP1_LITERAL(send1_opline), &ZEND_OP1_LITERAL(send2_opline));
  297. }
  298. if (RESULT_UNUSED(opline) &&
  299. !zend_memnstr(Z_STRVAL(ZEND_OP1_LITERAL(send1_opline)), "::", sizeof("::") - 1, Z_STRVAL(ZEND_OP1_LITERAL(send1_opline)) + Z_STRLEN(ZEND_OP1_LITERAL(send1_opline)))) {
  300. opline->opcode = ZEND_DECLARE_CONST;
  301. opline->op1_type = IS_CONST;
  302. opline->op2_type = IS_CONST;
  303. opline->result_type = IS_UNUSED;
  304. opline->op1.constant = send1_opline->op1.constant;
  305. opline->op2.constant = send2_opline->op1.constant;
  306. opline->result.num = 0;
  307. literal_dtor(&ZEND_OP2_LITERAL(init_opline));
  308. MAKE_NOP(init_opline);
  309. MAKE_NOP(send1_opline);
  310. MAKE_NOP(send2_opline);
  311. }
  312. break;
  313. }
  314. }
  315. /* pre-evaluate constant functions:
  316. constant(x)
  317. function_exists(x)
  318. is_callable(x)
  319. extension_loaded(x)
  320. */
  321. if (!send2_opline &&
  322. Z_TYPE(ZEND_OP1_LITERAL(send1_opline)) == IS_STRING) {
  323. if ((Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("function_exists")-1 &&
  324. !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)),
  325. "function_exists", sizeof("function_exists")-1)) ||
  326. (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("is_callable")-1 &&
  327. !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)),
  328. "is_callable", sizeof("is_callable")))) {
  329. zend_internal_function *func;
  330. zend_string *lc_name = zend_string_tolower(
  331. Z_STR(ZEND_OP1_LITERAL(send1_opline)));
  332. if ((func = zend_hash_find_ptr(EG(function_table), lc_name)) != NULL
  333. && func->type == ZEND_INTERNAL_FUNCTION
  334. && func->module->type == MODULE_PERSISTENT
  335. #ifdef ZEND_WIN32
  336. && func->module->handle == NULL
  337. #endif
  338. ) {
  339. zval t;
  340. ZVAL_TRUE(&t);
  341. literal_dtor(&ZEND_OP2_LITERAL(init_opline));
  342. MAKE_NOP(init_opline);
  343. literal_dtor(&ZEND_OP1_LITERAL(send1_opline));
  344. MAKE_NOP(send1_opline);
  345. if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_VAR, opline->result.var, &t)) {
  346. MAKE_NOP(opline);
  347. } else {
  348. opline->opcode = ZEND_QM_ASSIGN;
  349. opline->extended_value = 0;
  350. SET_UNUSED(opline->op2);
  351. zend_optimizer_update_op1_const(op_array, opline, &t);
  352. }
  353. }
  354. zend_string_release_ex(lc_name, 0);
  355. break;
  356. } else if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("extension_loaded")-1 &&
  357. !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)),
  358. "extension_loaded", sizeof("extension_loaded")-1)) {
  359. zval t;
  360. zend_string *lc_name = zend_string_tolower(
  361. Z_STR(ZEND_OP1_LITERAL(send1_opline)));
  362. zend_module_entry *m = zend_hash_find_ptr(&module_registry,
  363. lc_name);
  364. zend_string_release_ex(lc_name, 0);
  365. if (!m) {
  366. if (PG(enable_dl)) {
  367. break;
  368. } else {
  369. ZVAL_FALSE(&t);
  370. }
  371. } else {
  372. if (m->type == MODULE_PERSISTENT
  373. #ifdef ZEND_WIN32
  374. && m->handle == NULL
  375. #endif
  376. ) {
  377. ZVAL_TRUE(&t);
  378. } else {
  379. break;
  380. }
  381. }
  382. literal_dtor(&ZEND_OP2_LITERAL(init_opline));
  383. MAKE_NOP(init_opline);
  384. literal_dtor(&ZEND_OP1_LITERAL(send1_opline));
  385. MAKE_NOP(send1_opline);
  386. if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_VAR, opline->result.var, &t)) {
  387. MAKE_NOP(opline);
  388. } else {
  389. opline->opcode = ZEND_QM_ASSIGN;
  390. opline->extended_value = 0;
  391. SET_UNUSED(opline->op2);
  392. zend_optimizer_update_op1_const(op_array, opline, &t);
  393. }
  394. break;
  395. } else if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("constant")-1 &&
  396. !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)),
  397. "constant", sizeof("constant")-1)) {
  398. zval t;
  399. if (zend_optimizer_get_persistent_constant(Z_STR(ZEND_OP1_LITERAL(send1_opline)), &t, 1)) {
  400. literal_dtor(&ZEND_OP2_LITERAL(init_opline));
  401. MAKE_NOP(init_opline);
  402. literal_dtor(&ZEND_OP1_LITERAL(send1_opline));
  403. MAKE_NOP(send1_opline);
  404. if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_VAR, opline->result.var, &t)) {
  405. MAKE_NOP(opline);
  406. } else {
  407. opline->opcode = ZEND_QM_ASSIGN;
  408. opline->extended_value = 0;
  409. SET_UNUSED(opline->op2);
  410. zend_optimizer_update_op1_const(op_array, opline, &t);
  411. }
  412. }
  413. break;
  414. /* dirname(IS_CONST/IS_STRING) -> IS_CONST/IS_STRING */
  415. } else if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("dirname")-1 &&
  416. !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)),
  417. "dirname", sizeof("dirname") - 1) &&
  418. IS_ABSOLUTE_PATH(Z_STRVAL(ZEND_OP1_LITERAL(send1_opline)), Z_STRLEN(ZEND_OP1_LITERAL(send1_opline)))) {
  419. zend_string *dirname = zend_string_init(Z_STRVAL(ZEND_OP1_LITERAL(send1_opline)), Z_STRLEN(ZEND_OP1_LITERAL(send1_opline)), 0);
  420. ZSTR_LEN(dirname) = zend_dirname(ZSTR_VAL(dirname), ZSTR_LEN(dirname));
  421. if (IS_ABSOLUTE_PATH(ZSTR_VAL(dirname), ZSTR_LEN(dirname))) {
  422. zval t;
  423. ZVAL_STR(&t, dirname);
  424. literal_dtor(&ZEND_OP2_LITERAL(init_opline));
  425. MAKE_NOP(init_opline);
  426. literal_dtor(&ZEND_OP1_LITERAL(send1_opline));
  427. MAKE_NOP(send1_opline);
  428. if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_VAR, opline->result.var, &t)) {
  429. MAKE_NOP(opline);
  430. } else {
  431. opline->opcode = ZEND_QM_ASSIGN;
  432. opline->extended_value = 0;
  433. SET_UNUSED(opline->op2);
  434. zend_optimizer_update_op1_const(op_array, opline, &t);
  435. }
  436. } else {
  437. zend_string_release_ex(dirname, 0);
  438. }
  439. break;
  440. }
  441. }
  442. /* don't collect constants after any other function call */
  443. collect_constants = 0;
  444. break;
  445. }
  446. case ZEND_STRLEN:
  447. if (opline->op1_type == IS_CONST) {
  448. zval t;
  449. if (zend_optimizer_eval_strlen(&t, &ZEND_OP1_LITERAL(opline)) == SUCCESS) {
  450. literal_dtor(&ZEND_OP1_LITERAL(opline));
  451. if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_TMP_VAR, opline->result.var, &t)) {
  452. MAKE_NOP(opline);
  453. } else {
  454. opline->opcode = ZEND_QM_ASSIGN;
  455. zend_optimizer_update_op1_const(op_array, opline, &t);
  456. }
  457. }
  458. }
  459. break;
  460. case ZEND_DEFINED:
  461. {
  462. zval c;
  463. if (!zend_optimizer_get_persistent_constant(Z_STR(ZEND_OP1_LITERAL(opline)), &c, 0)) {
  464. break;
  465. }
  466. ZVAL_TRUE(&c);
  467. literal_dtor(&ZEND_OP1_LITERAL(opline));
  468. if (zend_optimizer_replace_by_const(op_array, opline, IS_TMP_VAR, opline->result.var, &c)) {
  469. MAKE_NOP(opline);
  470. } else {
  471. opline->opcode = ZEND_QM_ASSIGN;
  472. zend_optimizer_update_op1_const(op_array, opline, &c);
  473. }
  474. }
  475. break;
  476. case ZEND_DECLARE_CONST:
  477. if (collect_constants &&
  478. Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING &&
  479. Z_TYPE(ZEND_OP2_LITERAL(opline)) <= IS_STRING) {
  480. zend_optimizer_collect_constant(ctx, &ZEND_OP1_LITERAL(opline), &ZEND_OP2_LITERAL(opline));
  481. }
  482. break;
  483. #if 0
  484. /* see ext/opcache/tests/bug78961.phpt */
  485. // case ZEND_FETCH_R:
  486. case ZEND_FETCH_W:
  487. // case ZEND_FETCH_RW:
  488. case ZEND_FETCH_IS:
  489. // case ZEND_FETCH_FUNC_ARG:
  490. case ZEND_FETCH_UNSET:
  491. /* convert FETCH $GLOBALS (global), FETCH_DIM $x into FETCH $x (global) */
  492. if ((opline->extended_value & ZEND_FETCH_GLOBAL) != 0 &&
  493. opline->op1_type == IS_CONST &&
  494. Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING &&
  495. zend_string_equals_literal(Z_STR(ZEND_OP1_LITERAL(opline)), "GLOBALS") &&
  496. ((opline + 1)->opcode == opline->opcode + 1 ||
  497. ((opline + 1)->opcode == ZEND_UNSET_DIM &&
  498. opline->opcode == ZEND_FETCH_UNSET) ||
  499. ((opline + 1)->opcode == ZEND_ISSET_ISEMPTY_DIM_OBJ &&
  500. opline->opcode == ZEND_FETCH_IS)) &&
  501. (opline + 1)->op1_type == opline->result_type &&
  502. (opline + 1)->op1.var == opline->result.var &&
  503. ((opline + 1)->op2_type != IS_CONST ||
  504. Z_TYPE(ZEND_OP2_LITERAL(opline + 1)) < IS_ARRAY)) {
  505. if ((opline + 1)->opcode == ZEND_UNSET_DIM) {
  506. (opline + 1)->opcode = ZEND_UNSET_VAR;
  507. (opline + 1)->extended_value = ZEND_FETCH_GLOBAL;
  508. } else if ((opline + 1)->opcode == ZEND_ISSET_ISEMPTY_DIM_OBJ) {
  509. (opline + 1)->opcode = ZEND_ISSET_ISEMPTY_VAR;
  510. (opline + 1)->extended_value |= ZEND_FETCH_GLOBAL;
  511. } else {
  512. (opline + 1)->opcode = opline->opcode;
  513. (opline + 1)->extended_value = ZEND_FETCH_GLOBAL;
  514. }
  515. (opline + 1)->op1_type = (opline + 1)->op2_type;
  516. (opline + 1)->op1 = (opline + 1)->op2;
  517. if ((opline + 1)->op1_type == IS_CONST &&
  518. Z_TYPE(ZEND_OP1_LITERAL(opline + 1)) != IS_STRING) {
  519. convert_to_string(&ZEND_OP1_LITERAL(opline + 1));
  520. zend_string_hash_val(Z_STR(ZEND_OP1_LITERAL(opline + 1)));
  521. }
  522. SET_UNUSED((opline + 1)->op2);
  523. MAKE_NOP(opline);
  524. }
  525. break;
  526. #endif
  527. case ZEND_JMPZ_EX:
  528. case ZEND_JMPNZ_EX:
  529. /* convert Ti = JMPZ_EX(C, L) => Ti = QM_ASSIGN(C)
  530. in case we know it wouldn't jump */
  531. if (opline->op1_type == IS_CONST) {
  532. if (zend_is_true(&ZEND_OP1_LITERAL(opline))) {
  533. if (opline->opcode == ZEND_JMPZ_EX) {
  534. opline->opcode = ZEND_QM_ASSIGN;
  535. zval_ptr_dtor_nogc(&ZEND_OP1_LITERAL(opline));
  536. ZVAL_TRUE(&ZEND_OP1_LITERAL(opline));
  537. opline->op2.num = 0;
  538. break;
  539. }
  540. } else {
  541. if (opline->opcode == ZEND_JMPNZ_EX) {
  542. opline->opcode = ZEND_QM_ASSIGN;
  543. zval_ptr_dtor_nogc(&ZEND_OP1_LITERAL(opline));
  544. ZVAL_FALSE(&ZEND_OP1_LITERAL(opline));
  545. opline->op2.num = 0;
  546. break;
  547. }
  548. }
  549. }
  550. collect_constants = 0;
  551. break;
  552. case ZEND_JMPZ:
  553. case ZEND_JMPNZ:
  554. if (opline->op1_type == IS_CONST) {
  555. int should_jmp = zend_is_true(&ZEND_OP1_LITERAL(opline));
  556. if (opline->opcode == ZEND_JMPZ) {
  557. should_jmp = !should_jmp;
  558. }
  559. literal_dtor(&ZEND_OP1_LITERAL(opline));
  560. opline->op1_type = IS_UNUSED;
  561. if (should_jmp) {
  562. opline->opcode = ZEND_JMP;
  563. COPY_NODE(opline->op1, opline->op2);
  564. opline->op2.num = 0;
  565. } else {
  566. MAKE_NOP(opline);
  567. break;
  568. }
  569. }
  570. collect_constants = 0;
  571. break;
  572. case ZEND_JMPZNZ:
  573. if (opline->op1_type == IS_CONST) {
  574. zend_op *target_opline;
  575. if (zend_is_true(&ZEND_OP1_LITERAL(opline))) {
  576. target_opline = ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value); /* JMPNZ */
  577. } else {
  578. target_opline = ZEND_OP2_JMP_ADDR(opline); /* JMPZ */
  579. }
  580. literal_dtor(&ZEND_OP1_LITERAL(opline));
  581. ZEND_SET_OP_JMP_ADDR(opline, opline->op1, target_opline);
  582. opline->op1_type = IS_UNUSED;
  583. opline->opcode = ZEND_JMP;
  584. }
  585. collect_constants = 0;
  586. break;
  587. case ZEND_RETURN:
  588. case ZEND_RETURN_BY_REF:
  589. case ZEND_GENERATOR_RETURN:
  590. case ZEND_EXIT:
  591. case ZEND_THROW:
  592. case ZEND_MATCH_ERROR:
  593. case ZEND_CATCH:
  594. case ZEND_FAST_CALL:
  595. case ZEND_FAST_RET:
  596. case ZEND_JMP:
  597. case ZEND_FE_RESET_R:
  598. case ZEND_FE_RESET_RW:
  599. case ZEND_FE_FETCH_R:
  600. case ZEND_FE_FETCH_RW:
  601. case ZEND_JMP_SET:
  602. case ZEND_COALESCE:
  603. case ZEND_ASSERT_CHECK:
  604. case ZEND_JMP_NULL:
  605. case ZEND_VERIFY_NEVER_TYPE:
  606. collect_constants = 0;
  607. break;
  608. }
  609. opline++;
  610. }
  611. }