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