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
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 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->extended_value == ZEND_CONCAT && opline->op2_type == IS_CONST
108 && Z_TYPE(ZEND_OP2_LITERAL(opline)) != IS_STRING) {
109 convert_to_string(&ZEND_OP2_LITERAL(opline));
110 }
111 break;
112
113 case ZEND_CAST:
114 if (opline->op1_type == IS_CONST) {
115 /* cast of constant operand */
116 zval result;
117
118 if (zend_optimizer_eval_cast(&result, opline->extended_value, &ZEND_OP1_LITERAL(opline)) == SUCCESS) {
119 literal_dtor(&ZEND_OP1_LITERAL(opline));
120 if (zend_optimizer_replace_by_const(op_array, opline + 1, opline->result_type, opline->result.var, &result)) {
121 MAKE_NOP(opline);
122 } else {
123 opline->opcode = ZEND_QM_ASSIGN;
124 opline->extended_value = 0;
125 zend_optimizer_update_op1_const(op_array, opline, &result);
126 }
127 break;
128 }
129 }
130 break;
131
132 case ZEND_BW_NOT:
133 case ZEND_BOOL_NOT:
134 if (opline->op1_type == IS_CONST) {
135 /* unary operation on constant operand */
136 zval result;
137
138 if (zend_optimizer_eval_unary_op(&result, opline->opcode, &ZEND_OP1_LITERAL(opline)) == SUCCESS) {
139 literal_dtor(&ZEND_OP1_LITERAL(opline));
140 if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_TMP_VAR, opline->result.var, &result)) {
141 MAKE_NOP(opline);
142 } else {
143 opline->opcode = ZEND_QM_ASSIGN;
144 zend_optimizer_update_op1_const(op_array, opline, &result);
145 }
146 }
147 }
148 break;
149
150 case ZEND_FETCH_CONSTANT:
151 if (opline->op2_type == IS_CONST &&
152 Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING &&
153 Z_STRLEN(ZEND_OP2_LITERAL(opline)) == sizeof("__COMPILER_HALT_OFFSET__") - 1 &&
154 memcmp(Z_STRVAL(ZEND_OP2_LITERAL(opline)), "__COMPILER_HALT_OFFSET__", sizeof("__COMPILER_HALT_OFFSET__") - 1) == 0) {
155 /* substitute __COMPILER_HALT_OFFSET__ constant */
156 zend_execute_data *orig_execute_data = EG(current_execute_data);
157 zend_execute_data fake_execute_data;
158 zval *offset;
159
160 memset(&fake_execute_data, 0, sizeof(zend_execute_data));
161 fake_execute_data.func = (zend_function*)op_array;
162 EG(current_execute_data) = &fake_execute_data;
163 if ((offset = zend_get_constant_str("__COMPILER_HALT_OFFSET__", sizeof("__COMPILER_HALT_OFFSET__") - 1)) != NULL) {
164
165 literal_dtor(&ZEND_OP2_LITERAL(opline));
166 if (zend_optimizer_replace_by_const(op_array, opline, IS_TMP_VAR, opline->result.var, offset)) {
167 MAKE_NOP(opline);
168 } else {
169 opline->opcode = ZEND_QM_ASSIGN;
170 opline->extended_value = 0;
171 SET_UNUSED(opline->op2);
172 zend_optimizer_update_op1_const(op_array, opline, offset);
173 }
174 }
175 EG(current_execute_data) = orig_execute_data;
176 break;
177 }
178
179 if (opline->op2_type == IS_CONST &&
180 Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING) {
181 /* substitute persistent constants */
182 zval c;
183
184 if (!zend_optimizer_get_persistent_constant(Z_STR(ZEND_OP2_LITERAL(opline)), &c, 1)) {
185 if (!ctx->constants || !zend_optimizer_get_collected_constant(ctx->constants, &ZEND_OP2_LITERAL(opline), &c)) {
186 break;
187 }
188 }
189 if (Z_TYPE(c) == IS_CONSTANT_AST) {
190 break;
191 }
192 literal_dtor(&ZEND_OP2_LITERAL(opline));
193 if (zend_optimizer_replace_by_const(op_array, opline, IS_TMP_VAR, opline->result.var, &c)) {
194 MAKE_NOP(opline);
195 } else {
196 opline->opcode = ZEND_QM_ASSIGN;
197 opline->extended_value = 0;
198 SET_UNUSED(opline->op2);
199 zend_optimizer_update_op1_const(op_array, opline, &c);
200 }
201 }
202 break;
203
204 case ZEND_FETCH_CLASS_CONSTANT:
205 if (opline->op2_type == IS_CONST &&
206 Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING) {
207
208 zend_class_entry *ce = NULL;
209
210 if (opline->op1_type == IS_CONST &&
211 Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING) {
212 /* for A::B */
213 if (op_array->scope &&
214 zend_string_equals_ci(Z_STR(ZEND_OP1_LITERAL(opline)), op_array->scope->name)) {
215 ce = op_array->scope;
216 } else {
217 ce = zend_optimizer_get_class_entry(
218 ctx->script, Z_STR(op_array->literals[opline->op1.constant + 1]));
219 if (!ce) {
220 break;
221 }
222 }
223 } else if (op_array->scope &&
224 opline->op1_type == IS_UNUSED &&
225 (opline->op1.num & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_SELF) {
226 /* for self::B */
227 ce = op_array->scope;
228 } else if (op_array->scope &&
229 opline->op1_type == IS_VAR &&
230 (opline - 1)->opcode == ZEND_FETCH_CLASS &&
231 ((opline - 1)->op2_type == IS_UNUSED &&
232 ((opline - 1)->op1.num & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_SELF) &&
233 (opline - 1)->result.var == opline->op1.var) {
234 /* for self::B */
235 ce = op_array->scope;
236 }
237
238 if (ce) {
239 zend_class_constant *cc;
240 zval *c, t;
241
242 if ((cc = zend_hash_find_ptr(&ce->constants_table,
243 Z_STR(ZEND_OP2_LITERAL(opline)))) != NULL &&
244 (ZEND_CLASS_CONST_FLAGS(cc) & ZEND_ACC_PPP_MASK) == ZEND_ACC_PUBLIC) {
245 c = &cc->value;
246 if (Z_TYPE_P(c) == IS_CONSTANT_AST) {
247 zend_ast *ast = Z_ASTVAL_P(c);
248 if (ast->kind != ZEND_AST_CONSTANT
249 || !zend_optimizer_get_persistent_constant(zend_ast_get_constant_name(ast), &t, 1)
250 || Z_TYPE(t) == IS_CONSTANT_AST) {
251 break;
252 }
253 } else {
254 ZVAL_COPY_OR_DUP(&t, c);
255 }
256
257 if (opline->op1_type == IS_CONST) {
258 literal_dtor(&ZEND_OP1_LITERAL(opline));
259 } else if (opline->op1_type == IS_VAR) {
260 MAKE_NOP((opline - 1));
261 }
262 literal_dtor(&ZEND_OP2_LITERAL(opline));
263
264 if (zend_optimizer_replace_by_const(op_array, opline, IS_TMP_VAR, opline->result.var, &t)) {
265 MAKE_NOP(opline);
266 } else {
267 opline->opcode = ZEND_QM_ASSIGN;
268 opline->extended_value = 0;
269 SET_UNUSED(opline->op2);
270 zend_optimizer_update_op1_const(op_array, opline, &t);
271 }
272 }
273 }
274 }
275 break;
276
277 case ZEND_DO_ICALL: {
278 zend_op *send1_opline = opline - 1;
279 zend_op *send2_opline = NULL;
280 zend_op *init_opline = NULL;
281
282 while (send1_opline->opcode == ZEND_NOP) {
283 send1_opline--;
284 }
285 if (send1_opline->opcode != ZEND_SEND_VAL ||
286 send1_opline->op1_type != IS_CONST) {
287 /* don't collect constants after unknown function call */
288 collect_constants = 0;
289 break;
290 }
291 if (send1_opline->op2.num == 2) {
292 send2_opline = send1_opline;
293 send1_opline--;
294 while (send1_opline->opcode == ZEND_NOP) {
295 send1_opline--;
296 }
297 if (send1_opline->opcode != ZEND_SEND_VAL ||
298 send1_opline->op1_type != IS_CONST) {
299 /* don't collect constants after unknown function call */
300 collect_constants = 0;
301 break;
302 }
303 }
304 init_opline = send1_opline - 1;
305 while (init_opline->opcode == ZEND_NOP) {
306 init_opline--;
307 }
308 if (init_opline->opcode != ZEND_INIT_FCALL ||
309 init_opline->op2_type != IS_CONST ||
310 Z_TYPE(ZEND_OP2_LITERAL(init_opline)) != IS_STRING) {
311 /* don't collect constants after unknown function call */
312 collect_constants = 0;
313 break;
314 }
315
316 /* define("name", scalar); */
317 if (zend_string_equals_literal_ci(Z_STR(ZEND_OP2_LITERAL(init_opline)), "define")) {
318
319 if (Z_TYPE(ZEND_OP1_LITERAL(send1_opline)) == IS_STRING &&
320 send2_opline &&
321 Z_TYPE(ZEND_OP1_LITERAL(send2_opline)) <= IS_STRING) {
322
323 if (collect_constants) {
324 zend_optimizer_collect_constant(ctx, &ZEND_OP1_LITERAL(send1_opline), &ZEND_OP1_LITERAL(send2_opline));
325 }
326
327 if (RESULT_UNUSED(opline) &&
328 !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)))) {
329
330 opline->opcode = ZEND_DECLARE_CONST;
331 opline->op1_type = IS_CONST;
332 opline->op2_type = IS_CONST;
333 opline->result_type = IS_UNUSED;
334 opline->op1.constant = send1_opline->op1.constant;
335 opline->op2.constant = send2_opline->op1.constant;
336 opline->result.num = 0;
337
338 literal_dtor(&ZEND_OP2_LITERAL(init_opline));
339 MAKE_NOP(init_opline);
340 MAKE_NOP(send1_opline);
341 MAKE_NOP(send2_opline);
342 }
343 break;
344 }
345 }
346
347 /* pre-evaluate constant functions:
348 constant(x)
349 function_exists(x)
350 is_callable(x)
351 extension_loaded(x)
352 */
353 if (!send2_opline &&
354 Z_TYPE(ZEND_OP1_LITERAL(send1_opline)) == IS_STRING) {
355 if ((Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("function_exists")-1 &&
356 !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)),
357 "function_exists", sizeof("function_exists")-1)) ||
358 (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("is_callable")-1 &&
359 !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)),
360 "is_callable", sizeof("is_callable")))) {
361 zend_internal_function *func;
362 zend_string *lc_name = zend_string_tolower(
363 Z_STR(ZEND_OP1_LITERAL(send1_opline)));
364
365 if ((func = zend_hash_find_ptr(EG(function_table), lc_name)) != NULL
366 && func->type == ZEND_INTERNAL_FUNCTION
367 && func->module->type == MODULE_PERSISTENT
368 #ifdef ZEND_WIN32
369 && func->module->handle == NULL
370 #endif
371 ) {
372 zval t;
373 ZVAL_TRUE(&t);
374 literal_dtor(&ZEND_OP2_LITERAL(init_opline));
375 MAKE_NOP(init_opline);
376 literal_dtor(&ZEND_OP1_LITERAL(send1_opline));
377 MAKE_NOP(send1_opline);
378 if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_VAR, opline->result.var, &t)) {
379 MAKE_NOP(opline);
380 } else {
381 opline->opcode = ZEND_QM_ASSIGN;
382 opline->extended_value = 0;
383 SET_UNUSED(opline->op2);
384 zend_optimizer_update_op1_const(op_array, opline, &t);
385 }
386 }
387 zend_string_release_ex(lc_name, 0);
388 break;
389 } else if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("extension_loaded")-1 &&
390 !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)),
391 "extension_loaded", sizeof("extension_loaded")-1)) {
392 zval t;
393 zend_string *lc_name = zend_string_tolower(
394 Z_STR(ZEND_OP1_LITERAL(send1_opline)));
395 zend_module_entry *m = zend_hash_find_ptr(&module_registry,
396 lc_name);
397
398 zend_string_release_ex(lc_name, 0);
399 if (!m) {
400 if (PG(enable_dl)) {
401 break;
402 } else {
403 ZVAL_FALSE(&t);
404 }
405 } else {
406 if (m->type == MODULE_PERSISTENT
407 #ifdef ZEND_WIN32
408 && m->handle == NULL
409 #endif
410 ) {
411 ZVAL_TRUE(&t);
412 } else {
413 break;
414 }
415 }
416
417 literal_dtor(&ZEND_OP2_LITERAL(init_opline));
418 MAKE_NOP(init_opline);
419 literal_dtor(&ZEND_OP1_LITERAL(send1_opline));
420 MAKE_NOP(send1_opline);
421 if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_VAR, opline->result.var, &t)) {
422 MAKE_NOP(opline);
423 } else {
424 opline->opcode = ZEND_QM_ASSIGN;
425 opline->extended_value = 0;
426 SET_UNUSED(opline->op2);
427 zend_optimizer_update_op1_const(op_array, opline, &t);
428 }
429 break;
430 } else if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("constant")-1 &&
431 !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)),
432 "constant", sizeof("constant")-1)) {
433 zval t;
434
435 if (zend_optimizer_get_persistent_constant(Z_STR(ZEND_OP1_LITERAL(send1_opline)), &t, 1)) {
436 literal_dtor(&ZEND_OP2_LITERAL(init_opline));
437 MAKE_NOP(init_opline);
438 literal_dtor(&ZEND_OP1_LITERAL(send1_opline));
439 MAKE_NOP(send1_opline);
440 if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_VAR, opline->result.var, &t)) {
441 MAKE_NOP(opline);
442 } else {
443 opline->opcode = ZEND_QM_ASSIGN;
444 opline->extended_value = 0;
445 SET_UNUSED(opline->op2);
446 zend_optimizer_update_op1_const(op_array, opline, &t);
447 }
448 }
449 break;
450 /* dirname(IS_CONST/IS_STRING) -> IS_CONST/IS_STRING */
451 } else if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("dirname")-1 &&
452 !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)),
453 "dirname", sizeof("dirname") - 1) &&
454 IS_ABSOLUTE_PATH(Z_STRVAL(ZEND_OP1_LITERAL(send1_opline)), Z_STRLEN(ZEND_OP1_LITERAL(send1_opline)))) {
455 zend_string *dirname = zend_string_init(Z_STRVAL(ZEND_OP1_LITERAL(send1_opline)), Z_STRLEN(ZEND_OP1_LITERAL(send1_opline)), 0);
456 ZSTR_LEN(dirname) = zend_dirname(ZSTR_VAL(dirname), ZSTR_LEN(dirname));
457 if (IS_ABSOLUTE_PATH(ZSTR_VAL(dirname), ZSTR_LEN(dirname))) {
458 zval t;
459
460 ZVAL_STR(&t, dirname);
461 literal_dtor(&ZEND_OP2_LITERAL(init_opline));
462 MAKE_NOP(init_opline);
463 literal_dtor(&ZEND_OP1_LITERAL(send1_opline));
464 MAKE_NOP(send1_opline);
465 if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_VAR, opline->result.var, &t)) {
466 MAKE_NOP(opline);
467 } else {
468 opline->opcode = ZEND_QM_ASSIGN;
469 opline->extended_value = 0;
470 SET_UNUSED(opline->op2);
471 zend_optimizer_update_op1_const(op_array, opline, &t);
472 }
473 } else {
474 zend_string_release_ex(dirname, 0);
475 }
476 break;
477 }
478 }
479 /* don't collect constants after any other function call */
480 collect_constants = 0;
481 break;
482 }
483 case ZEND_STRLEN:
484 if (opline->op1_type == IS_CONST) {
485 zval t;
486
487 if (zend_optimizer_eval_strlen(&t, &ZEND_OP1_LITERAL(opline)) == SUCCESS) {
488 literal_dtor(&ZEND_OP1_LITERAL(opline));
489 if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_TMP_VAR, opline->result.var, &t)) {
490 MAKE_NOP(opline);
491 } else {
492 opline->opcode = ZEND_QM_ASSIGN;
493 zend_optimizer_update_op1_const(op_array, opline, &t);
494 }
495 }
496 }
497 break;
498 case ZEND_DEFINED:
499 {
500 zval c;
501 if (!zend_optimizer_get_persistent_constant(Z_STR(ZEND_OP1_LITERAL(opline)), &c, 0)) {
502 break;
503 }
504 ZVAL_TRUE(&c);
505 literal_dtor(&ZEND_OP1_LITERAL(opline));
506 if (zend_optimizer_replace_by_const(op_array, opline, IS_TMP_VAR, opline->result.var, &c)) {
507 MAKE_NOP(opline);
508 } else {
509 opline->opcode = ZEND_QM_ASSIGN;
510 zend_optimizer_update_op1_const(op_array, opline, &c);
511 }
512 }
513 break;
514 case ZEND_DECLARE_CONST:
515 if (collect_constants &&
516 Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING &&
517 Z_TYPE(ZEND_OP2_LITERAL(opline)) <= IS_STRING) {
518 zend_optimizer_collect_constant(ctx, &ZEND_OP1_LITERAL(opline), &ZEND_OP2_LITERAL(opline));
519 }
520 break;
521 #if 0
522 /* see ext/opcache/tests/bug78961.phpt */
523 // case ZEND_FETCH_R:
524 case ZEND_FETCH_W:
525 // case ZEND_FETCH_RW:
526 case ZEND_FETCH_IS:
527 // case ZEND_FETCH_FUNC_ARG:
528 case ZEND_FETCH_UNSET:
529 /* convert FETCH $GLOBALS (global), FETCH_DIM $x into FETCH $x (global) */
530 if ((opline->extended_value & ZEND_FETCH_GLOBAL) != 0 &&
531 opline->op1_type == IS_CONST &&
532 Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING &&
533 zend_string_equals_literal(Z_STR(ZEND_OP1_LITERAL(opline)), "GLOBALS") &&
534 ((opline + 1)->opcode == opline->opcode + 1 ||
535 ((opline + 1)->opcode == ZEND_UNSET_DIM &&
536 opline->opcode == ZEND_FETCH_UNSET) ||
537 ((opline + 1)->opcode == ZEND_ISSET_ISEMPTY_DIM_OBJ &&
538 opline->opcode == ZEND_FETCH_IS)) &&
539 (opline + 1)->op1_type == opline->result_type &&
540 (opline + 1)->op1.var == opline->result.var &&
541 ((opline + 1)->op2_type != IS_CONST ||
542 Z_TYPE(ZEND_OP2_LITERAL(opline + 1)) < IS_ARRAY)) {
543
544 if ((opline + 1)->opcode == ZEND_UNSET_DIM) {
545 (opline + 1)->opcode = ZEND_UNSET_VAR;
546 (opline + 1)->extended_value = ZEND_FETCH_GLOBAL;
547 } else if ((opline + 1)->opcode == ZEND_ISSET_ISEMPTY_DIM_OBJ) {
548 (opline + 1)->opcode = ZEND_ISSET_ISEMPTY_VAR;
549 (opline + 1)->extended_value |= ZEND_FETCH_GLOBAL;
550 } else {
551 (opline + 1)->opcode = opline->opcode;
552 (opline + 1)->extended_value = ZEND_FETCH_GLOBAL;
553 }
554 (opline + 1)->op1_type = (opline + 1)->op2_type;
555 (opline + 1)->op1 = (opline + 1)->op2;
556 if ((opline + 1)->op1_type == IS_CONST &&
557 Z_TYPE(ZEND_OP1_LITERAL(opline + 1)) != IS_STRING) {
558
559 convert_to_string(&ZEND_OP1_LITERAL(opline + 1));
560 zend_string_hash_val(Z_STR(ZEND_OP1_LITERAL(opline + 1)));
561 }
562 SET_UNUSED((opline + 1)->op2);
563 MAKE_NOP(opline);
564 }
565 break;
566 #endif
567
568 case ZEND_JMPZ_EX:
569 case ZEND_JMPNZ_EX:
570 /* convert Ti = JMPZ_EX(C, L) => Ti = QM_ASSIGN(C)
571 in case we know it wouldn't jump */
572 if (opline->op1_type == IS_CONST) {
573 if (zend_is_true(&ZEND_OP1_LITERAL(opline))) {
574 if (opline->opcode == ZEND_JMPZ_EX) {
575 opline->opcode = ZEND_QM_ASSIGN;
576 zval_ptr_dtor_nogc(&ZEND_OP1_LITERAL(opline));
577 ZVAL_TRUE(&ZEND_OP1_LITERAL(opline));
578 opline->op2.num = 0;
579 break;
580 }
581 } else {
582 if (opline->opcode == ZEND_JMPNZ_EX) {
583 opline->opcode = ZEND_QM_ASSIGN;
584 zval_ptr_dtor_nogc(&ZEND_OP1_LITERAL(opline));
585 ZVAL_FALSE(&ZEND_OP1_LITERAL(opline));
586 opline->op2.num = 0;
587 break;
588 }
589 }
590 }
591 collect_constants = 0;
592 break;
593
594 case ZEND_JMPZ:
595 case ZEND_JMPNZ:
596 if (opline->op1_type == IS_CONST) {
597 int should_jmp = zend_is_true(&ZEND_OP1_LITERAL(opline));
598
599 if (opline->opcode == ZEND_JMPZ) {
600 should_jmp = !should_jmp;
601 }
602 literal_dtor(&ZEND_OP1_LITERAL(opline));
603 opline->op1_type = IS_UNUSED;
604 if (should_jmp) {
605 opline->opcode = ZEND_JMP;
606 COPY_NODE(opline->op1, opline->op2);
607 opline->op2.num = 0;
608 } else {
609 MAKE_NOP(opline);
610 break;
611 }
612 }
613 collect_constants = 0;
614 break;
615
616 case ZEND_JMPZNZ:
617 if (opline->op1_type == IS_CONST) {
618 zend_op *target_opline;
619
620 if (zend_is_true(&ZEND_OP1_LITERAL(opline))) {
621 target_opline = ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value); /* JMPNZ */
622 } else {
623 target_opline = ZEND_OP2_JMP_ADDR(opline); /* JMPZ */
624 }
625 literal_dtor(&ZEND_OP1_LITERAL(opline));
626 ZEND_SET_OP_JMP_ADDR(opline, opline->op1, target_opline);
627 opline->op1_type = IS_UNUSED;
628 opline->opcode = ZEND_JMP;
629 }
630 collect_constants = 0;
631 break;
632
633 case ZEND_RETURN:
634 case ZEND_RETURN_BY_REF:
635 case ZEND_GENERATOR_RETURN:
636 case ZEND_EXIT:
637 case ZEND_THROW:
638 case ZEND_MATCH_ERROR:
639 case ZEND_CATCH:
640 case ZEND_FAST_CALL:
641 case ZEND_FAST_RET:
642 case ZEND_JMP:
643 case ZEND_FE_RESET_R:
644 case ZEND_FE_RESET_RW:
645 case ZEND_FE_FETCH_R:
646 case ZEND_FE_FETCH_RW:
647 case ZEND_JMP_SET:
648 case ZEND_COALESCE:
649 case ZEND_ASSERT_CHECK:
650 case ZEND_JMP_NULL:
651 case ZEND_VERIFY_NEVER_TYPE:
652 collect_constants = 0;
653 break;
654 }
655 opline++;
656 }
657 }
658