1 /*
2 +----------------------------------------------------------------------+
3 | Zend OPcache |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1998-2018 The PHP Group |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Authors: Andi Gutmans <andi@zend.com> |
16 | Zeev Suraski <zeev@zend.com> |
17 | Stanislav Malyshev <stas@zend.com> |
18 | Dmitry Stogov <dmitry@zend.com> |
19 +----------------------------------------------------------------------+
20 */
21
22 /* pass 1
23 * - substitute persistent constants (true, false, null, etc)
24 * - perform compile-time evaluation of constant binary and unary operations
25 * - optimize series of ADD_STRING and/or ADD_CHAR
26 * - convert CAST(IS_BOOL,x) into BOOL(x)
27 * - pre-evaluate constant function calls
28 */
29
30 #include "php.h"
31 #include "Optimizer/zend_optimizer.h"
32 #include "Optimizer/zend_optimizer_internal.h"
33 #include "zend_API.h"
34 #include "zend_constants.h"
35 #include "zend_execute.h"
36 #include "zend_vm.h"
37
38 #define ZEND_IS_CONSTANT_TYPE(t) ((t) == IS_CONSTANT)
39
zend_optimizer_pass1(zend_op_array * op_array,zend_optimizer_ctx * ctx)40 void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx)
41 {
42 int i = 0;
43 zend_op *opline = op_array->opcodes;
44 zend_op *end = opline + op_array->last;
45 zend_bool collect_constants = (ZEND_OPTIMIZER_PASS_15 & ctx->optimization_level)?
46 (op_array == &ctx->script->main_op_array) : 0;
47
48 while (opline < end) {
49 switch (opline->opcode) {
50 case ZEND_ADD:
51 case ZEND_SUB:
52 case ZEND_MUL:
53 case ZEND_DIV:
54 case ZEND_MOD:
55 case ZEND_POW:
56 case ZEND_SL:
57 case ZEND_SR:
58 case ZEND_CONCAT:
59 case ZEND_FAST_CONCAT:
60 case ZEND_IS_EQUAL:
61 case ZEND_IS_NOT_EQUAL:
62 case ZEND_IS_SMALLER:
63 case ZEND_IS_SMALLER_OR_EQUAL:
64 case ZEND_IS_IDENTICAL:
65 case ZEND_IS_NOT_IDENTICAL:
66 case ZEND_BW_OR:
67 case ZEND_BW_AND:
68 case ZEND_BW_XOR:
69 case ZEND_BOOL_XOR:
70 case ZEND_SPACESHIP:
71 if (ZEND_OP1_TYPE(opline) == IS_CONST &&
72 ZEND_OP2_TYPE(opline) == IS_CONST) {
73 /* binary operation with constant operands */
74 binary_op_type binary_op = get_binary_op(opline->opcode);
75 uint32_t tv = ZEND_RESULT(opline).var; /* temporary variable */
76 zval result;
77 int er;
78
79 if ((opline->opcode == ZEND_DIV || opline->opcode == ZEND_MOD) &&
80 zval_get_long(&ZEND_OP2_LITERAL(opline)) == 0) {
81 /* div by 0 */
82 break;
83 } else if ((opline->opcode == ZEND_SL || opline->opcode == ZEND_SR) &&
84 zval_get_long(&ZEND_OP2_LITERAL(opline)) < 0) {
85 /* shift by negative number */
86 break;
87 } else if (zend_binary_op_produces_numeric_string_error(opline->opcode, &ZEND_OP1_LITERAL(opline), &ZEND_OP2_LITERAL(opline))) {
88 /* produces numeric string E_NOTICE/E_WARNING */
89 break;
90 }
91 er = EG(error_reporting);
92 EG(error_reporting) = 0;
93 /* evaluate constant expression */
94 if (binary_op(&result, &ZEND_OP1_LITERAL(opline), &ZEND_OP2_LITERAL(opline)) != SUCCESS) {
95 EG(error_reporting) = er;
96 break;
97 }
98 EG(error_reporting) = er;
99
100 if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_TMP_VAR, tv, &result)) {
101 literal_dtor(&ZEND_OP1_LITERAL(opline));
102 literal_dtor(&ZEND_OP2_LITERAL(opline));
103 MAKE_NOP(opline);
104 }
105 }
106 break;
107
108 case ZEND_CAST:
109 if (ZEND_OP1_TYPE(opline) == IS_CONST &&
110 opline->extended_value != IS_ARRAY &&
111 opline->extended_value != IS_OBJECT &&
112 opline->extended_value != IS_RESOURCE &&
113 (opline->extended_value != IS_STRING
114 || Z_TYPE(ZEND_OP1_LITERAL(opline)) != IS_ARRAY)) {
115 /* cast of constant operand */
116 zend_uchar type = opline->result_type;
117 uint32_t tv = ZEND_RESULT(opline).var; /* temporary variable */
118 zval res;
119 res = ZEND_OP1_LITERAL(opline);
120 zval_copy_ctor(&res);
121 switch (opline->extended_value) {
122 case IS_NULL:
123 convert_to_null(&res);
124 break;
125 case _IS_BOOL:
126 convert_to_boolean(&res);
127 break;
128 case IS_LONG:
129 convert_to_long(&res);
130 break;
131 case IS_DOUBLE:
132 convert_to_double(&res);
133 break;
134 case IS_STRING:
135 convert_to_string(&res);
136 break;
137 }
138
139 if (zend_optimizer_replace_by_const(op_array, opline + 1, type, tv, &res)) {
140 literal_dtor(&ZEND_OP1_LITERAL(opline));
141 MAKE_NOP(opline);
142 }
143 } else if (opline->extended_value == _IS_BOOL) {
144 /* T = CAST(X, IS_BOOL) => T = BOOL(X) */
145 opline->opcode = ZEND_BOOL;
146 opline->extended_value = 0;
147 }
148 break;
149
150 case ZEND_BW_NOT:
151 case ZEND_BOOL_NOT:
152 if (ZEND_OP1_TYPE(opline) == IS_CONST) {
153 /* unary operation on constant operand */
154 unary_op_type unary_op = get_unary_op(opline->opcode);
155 zval result;
156 uint32_t tv = ZEND_RESULT(opline).var; /* temporary variable */
157 int er;
158
159 er = EG(error_reporting);
160 EG(error_reporting) = 0;
161 if (unary_op(&result, &ZEND_OP1_LITERAL(opline)) != SUCCESS) {
162 EG(error_reporting) = er;
163 break;
164 }
165 EG(error_reporting) = er;
166
167 if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_TMP_VAR, tv, &result)) {
168 literal_dtor(&ZEND_OP1_LITERAL(opline));
169 MAKE_NOP(opline);
170 }
171 }
172 break;
173
174 #if 0
175 case ZEND_ADD_STRING:
176 case ZEND_ADD_CHAR:
177 {
178 zend_op *next_op = opline + 1;
179 int requires_conversion = (opline->opcode == ZEND_ADD_CHAR? 1 : 0);
180 size_t final_length = 0;
181 zend_string *str;
182 char *ptr;
183 zend_op *last_op;
184
185 /* There is always a ZEND_RETURN at the end
186 if (next_op>=end) {
187 break;
188 }
189 */
190 while (next_op->opcode == ZEND_ADD_STRING || next_op->opcode == ZEND_ADD_CHAR) {
191 if (ZEND_RESULT(opline).var != ZEND_RESULT(next_op).var) {
192 break;
193 }
194 if (next_op->opcode == ZEND_ADD_CHAR) {
195 final_length += 1;
196 } else { /* ZEND_ADD_STRING */
197 final_length += Z_STRLEN(ZEND_OP2_LITERAL(next_op));
198 }
199 next_op++;
200 }
201 if (final_length == 0) {
202 break;
203 }
204 last_op = next_op;
205 final_length += (requires_conversion? 1 : Z_STRLEN(ZEND_OP2_LITERAL(opline)));
206 str = zend_string_alloc(final_length, 0);
207 str->len = final_length;
208 ptr = str->val;
209 ptr[final_length] = '\0';
210 if (requires_conversion) { /* ZEND_ADD_CHAR */
211 char chval = (char)Z_LVAL(ZEND_OP2_LITERAL(opline));
212
213 ZVAL_NEW_STR(&ZEND_OP2_LITERAL(opline), str);
214 ptr[0] = chval;
215 opline->opcode = ZEND_ADD_STRING;
216 ptr++;
217 } else { /* ZEND_ADD_STRING */
218 memcpy(ptr, Z_STRVAL(ZEND_OP2_LITERAL(opline)), Z_STRLEN(ZEND_OP2_LITERAL(opline)));
219 ptr += Z_STRLEN(ZEND_OP2_LITERAL(opline));
220 zend_string_release(Z_STR(ZEND_OP2_LITERAL(opline)));
221 ZVAL_NEW_STR(&ZEND_OP2_LITERAL(opline), str);
222 }
223 next_op = opline + 1;
224 while (next_op < last_op) {
225 if (next_op->opcode == ZEND_ADD_STRING) {
226 memcpy(ptr, Z_STRVAL(ZEND_OP2_LITERAL(next_op)), Z_STRLEN(ZEND_OP2_LITERAL(next_op)));
227 ptr += Z_STRLEN(ZEND_OP2_LITERAL(next_op));
228 literal_dtor(&ZEND_OP2_LITERAL(next_op));
229 } else { /* ZEND_ADD_CHAR */
230 *ptr = (char)Z_LVAL(ZEND_OP2_LITERAL(next_op));
231 ptr++;
232 }
233 MAKE_NOP(next_op);
234 next_op++;
235 }
236 if (!((ZEND_OPTIMIZER_PASS_5|ZEND_OPTIMIZER_PASS_10) & OPTIMIZATION_LEVEL)) {
237 /* NOP removal is disabled => insert JMP over NOPs */
238 if (last_op-opline >= 3) { /* If we have more than 2 NOPS then JMP over them */
239 (opline + 1)->opcode = ZEND_JMP;
240 ZEND_OP1(opline + 1).opline_num = last_op - op_array->opcodes; /* that's OK even for ZE2, since opline_num's are resolved in pass 2 later */
241 }
242 }
243 }
244 break;
245 #endif
246
247 case ZEND_FETCH_CONSTANT:
248 if (ZEND_OP2_TYPE(opline) == IS_CONST &&
249 Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING &&
250 Z_STRLEN(ZEND_OP2_LITERAL(opline)) == sizeof("__COMPILER_HALT_OFFSET__") - 1 &&
251 memcmp(Z_STRVAL(ZEND_OP2_LITERAL(opline)), "__COMPILER_HALT_OFFSET__", sizeof("__COMPILER_HALT_OFFSET__") - 1) == 0) {
252 /* substitute __COMPILER_HALT_OFFSET__ constant */
253 zend_execute_data *orig_execute_data = EG(current_execute_data);
254 zend_execute_data fake_execute_data;
255 zval *offset;
256
257 memset(&fake_execute_data, 0, sizeof(zend_execute_data));
258 fake_execute_data.func = (zend_function*)op_array;
259 EG(current_execute_data) = &fake_execute_data;
260 if ((offset = zend_get_constant_str("__COMPILER_HALT_OFFSET__", sizeof("__COMPILER_HALT_OFFSET__") - 1)) != NULL) {
261 uint32_t tv = ZEND_RESULT(opline).var;
262
263 if (zend_optimizer_replace_by_const(op_array, opline, IS_TMP_VAR, tv, offset)) {
264 literal_dtor(&ZEND_OP2_LITERAL(opline));
265 MAKE_NOP(opline);
266 }
267 }
268 EG(current_execute_data) = orig_execute_data;
269 break;
270 }
271
272 if (ZEND_OP2_TYPE(opline) == IS_CONST &&
273 Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING) {
274 /* substitute persistent constants */
275 uint32_t tv = ZEND_RESULT(opline).var;
276 zval c;
277
278 if (!zend_optimizer_get_persistent_constant(Z_STR(ZEND_OP2_LITERAL(opline)), &c, 1)) {
279 if (!ctx->constants || !zend_optimizer_get_collected_constant(ctx->constants, &ZEND_OP2_LITERAL(opline), &c)) {
280 break;
281 }
282 }
283 if (Z_TYPE(c) == IS_CONSTANT_AST) {
284 break;
285 }
286 if (zend_optimizer_replace_by_const(op_array, opline, IS_TMP_VAR, tv, &c)) {
287 literal_dtor(&ZEND_OP2_LITERAL(opline));
288 MAKE_NOP(opline);
289 }
290 }
291 break;
292
293 case ZEND_FETCH_CLASS_CONSTANT:
294 if (ZEND_OP2_TYPE(opline) == IS_CONST &&
295 Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING) {
296
297 zend_class_entry *ce = NULL;
298
299 if (ZEND_OP1_TYPE(opline) == IS_CONST &&
300 Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING) {
301 /* for A::B */
302 if (op_array->scope &&
303 !strncasecmp(Z_STRVAL(ZEND_OP1_LITERAL(opline)),
304 ZSTR_VAL(op_array->scope->name), Z_STRLEN(ZEND_OP1_LITERAL(opline)) + 1)) {
305 ce = op_array->scope;
306 } else {
307 if ((ce = zend_hash_find_ptr(EG(class_table),
308 Z_STR(op_array->literals[opline->op1.constant + 1]))) == NULL ||
309 (ce->type == ZEND_INTERNAL_CLASS &&
310 ce->info.internal.module->type != MODULE_PERSISTENT) ||
311 (ce->type == ZEND_USER_CLASS &&
312 ce->info.user.filename != op_array->filename)) {
313 break;
314 }
315 }
316 } else if (op_array->scope &&
317 ZEND_OP1_TYPE(opline) == IS_UNUSED &&
318 (opline->op1.num & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_SELF) {
319 /* for self::B */
320 ce = op_array->scope;
321 } else if (op_array->scope &&
322 ZEND_OP1_TYPE(opline) == IS_VAR &&
323 (opline - 1)->opcode == ZEND_FETCH_CLASS &&
324 (ZEND_OP1_TYPE(opline - 1) == IS_UNUSED &&
325 ((opline - 1)->extended_value & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_SELF) &&
326 ZEND_RESULT((opline - 1)).var == ZEND_OP1(opline).var) {
327 /* for self::B */
328 ce = op_array->scope;
329 }
330
331 if (ce) {
332 uint32_t tv = ZEND_RESULT(opline).var;
333 zend_class_constant *cc;
334 zval *c, t;
335
336 if ((cc = zend_hash_find_ptr(&ce->constants_table,
337 Z_STR(ZEND_OP2_LITERAL(opline)))) != NULL &&
338 (Z_ACCESS_FLAGS(cc->value) & ZEND_ACC_PPP_MASK) == ZEND_ACC_PUBLIC) {
339 c = &cc->value;
340 if (Z_TYPE_P(c) == IS_CONSTANT_AST) {
341 break;
342 }
343 if (ZEND_IS_CONSTANT_TYPE(Z_TYPE_P(c))) {
344 if (!zend_optimizer_get_persistent_constant(Z_STR_P(c), &t, 1) ||
345 ZEND_IS_CONSTANT_TYPE(Z_TYPE(t))) {
346 break;
347 }
348 } else {
349 ZVAL_COPY_VALUE(&t, c);
350 zval_copy_ctor(&t);
351 }
352
353 if (zend_optimizer_replace_by_const(op_array, opline, IS_TMP_VAR, tv, &t)) {
354 if (ZEND_OP1_TYPE(opline) == IS_CONST) {
355 literal_dtor(&ZEND_OP1_LITERAL(opline));
356 } else if (ZEND_OP1_TYPE(opline) == IS_VAR) {
357 MAKE_NOP((opline - 1));
358 }
359 literal_dtor(&ZEND_OP2_LITERAL(opline));
360 MAKE_NOP(opline);
361 }
362 }
363 }
364 }
365 break;
366
367 case ZEND_DO_ICALL: {
368 zend_op *send1_opline = opline - 1;
369 zend_op *send2_opline = NULL;
370 zend_op *init_opline = NULL;
371
372 while (send1_opline->opcode == ZEND_NOP) {
373 send1_opline--;
374 }
375 if (send1_opline->opcode != ZEND_SEND_VAL ||
376 ZEND_OP1_TYPE(send1_opline) != IS_CONST) {
377 /* don't colllect constants after unknown function call */
378 collect_constants = 0;
379 break;
380 }
381 if (send1_opline->op2.num == 2) {
382 send2_opline = send1_opline;
383 send1_opline--;
384 while (send1_opline->opcode == ZEND_NOP) {
385 send1_opline--;
386 }
387 if (send1_opline->opcode != ZEND_SEND_VAL ||
388 ZEND_OP1_TYPE(send1_opline) != IS_CONST) {
389 /* don't colllect constants after unknown function call */
390 collect_constants = 0;
391 break;
392 }
393 }
394 init_opline = send1_opline - 1;
395 while (init_opline->opcode == ZEND_NOP) {
396 init_opline--;
397 }
398 if (init_opline->opcode != ZEND_INIT_FCALL ||
399 ZEND_OP2_TYPE(init_opline) != IS_CONST ||
400 Z_TYPE(ZEND_OP2_LITERAL(init_opline)) != IS_STRING) {
401 /* don't colllect constants after unknown function call */
402 collect_constants = 0;
403 break;
404 }
405
406 /* define("name", scalar); */
407 if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("define")-1 &&
408 zend_binary_strcasecmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)), Z_STRLEN(ZEND_OP2_LITERAL(init_opline)), "define", sizeof("define")-1) == 0) {
409
410 if (Z_TYPE(ZEND_OP1_LITERAL(send1_opline)) == IS_STRING &&
411 send2_opline &&
412 Z_TYPE(ZEND_OP1_LITERAL(send2_opline)) <= IS_STRING) {
413
414 if (collect_constants) {
415 zend_optimizer_collect_constant(ctx, &ZEND_OP1_LITERAL(send1_opline), &ZEND_OP1_LITERAL(send2_opline));
416 }
417
418 if (RESULT_UNUSED(opline) &&
419 !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)))) {
420
421 opline->opcode = ZEND_DECLARE_CONST;
422 opline->op1_type = IS_CONST;
423 opline->op2_type = IS_CONST;
424 opline->result_type = IS_UNUSED;
425 opline->op1.constant = send1_opline->op1.constant;
426 opline->op2.constant = send2_opline->op1.constant;
427 opline->result.num = 0;
428
429 literal_dtor(&ZEND_OP2_LITERAL(init_opline));
430 MAKE_NOP(init_opline);
431 MAKE_NOP(send1_opline);
432 MAKE_NOP(send2_opline);
433 }
434 break;
435 }
436 }
437
438 /* pre-evaluate constant functions:
439 defined(x)
440 constant(x)
441 function_exists(x)
442 is_callable(x)
443 extension_loaded(x)
444 */
445 if (!send2_opline &&
446 Z_TYPE(ZEND_OP1_LITERAL(send1_opline)) == IS_STRING) {
447 if ((Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("function_exists")-1 &&
448 !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)),
449 "function_exists", sizeof("function_exists")-1) &&
450 !zend_optimizer_is_disabled_func("function_exists", sizeof("function_exists") - 1)) ||
451 (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("is_callable")-1 &&
452 !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)),
453 "is_callable", sizeof("is_callable")) &&
454 !zend_optimizer_is_disabled_func("is_callable", sizeof("is_callable") - 1))) {
455 zend_internal_function *func;
456 zend_string *lc_name = zend_string_tolower(
457 Z_STR(ZEND_OP1_LITERAL(send1_opline)));
458
459 if ((func = zend_hash_find_ptr(EG(function_table), lc_name)) != NULL
460 && func->type == ZEND_INTERNAL_FUNCTION
461 && func->module->type == MODULE_PERSISTENT
462 #ifdef ZEND_WIN32
463 && func->module->handle == NULL
464 #endif
465 ) {
466 zval t;
467 if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("is_callable") - 1 ||
468 func->handler != ZEND_FN(display_disabled_function)) {
469 ZVAL_TRUE(&t);
470 } else {
471 ZVAL_FALSE(&t);
472 }
473 if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_VAR, ZEND_RESULT(opline).var, &t)) {
474 literal_dtor(&ZEND_OP2_LITERAL(init_opline));
475 MAKE_NOP(init_opline);
476 literal_dtor(&ZEND_OP1_LITERAL(send1_opline));
477 MAKE_NOP(send1_opline);
478 MAKE_NOP(opline);
479 zend_string_release(lc_name);
480 break;
481 }
482 }
483 zend_string_release(lc_name);
484 } else if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("extension_loaded")-1 &&
485 !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)),
486 "extension_loaded", sizeof("extension_loaded")-1) &&
487 !zend_optimizer_is_disabled_func("extension_loaded", sizeof("extension_loaded") - 1)) {
488 zval t;
489 zend_string *lc_name = zend_string_tolower(
490 Z_STR(ZEND_OP1_LITERAL(send1_opline)));
491 zend_module_entry *m = zend_hash_find_ptr(&module_registry,
492 lc_name);
493
494 zend_string_release(lc_name);
495 if (!m) {
496 if (PG(enable_dl)) {
497 break;
498 } else {
499 ZVAL_FALSE(&t);
500 }
501 } else {
502 if (m->type == MODULE_PERSISTENT
503 #ifdef ZEND_WIN32
504 && m->handle == NULL
505 #endif
506 ) {
507 ZVAL_TRUE(&t);
508 } else {
509 break;
510 }
511 }
512
513 if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_VAR, ZEND_RESULT(opline).var, &t)) {
514 literal_dtor(&ZEND_OP2_LITERAL(init_opline));
515 MAKE_NOP(init_opline);
516 literal_dtor(&ZEND_OP1_LITERAL(send1_opline));
517 MAKE_NOP(send1_opline);
518 MAKE_NOP(opline);
519 break;
520 }
521 } else if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("defined")-1 &&
522 !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)),
523 "defined", sizeof("defined")-1) &&
524 !zend_optimizer_is_disabled_func("defined", sizeof("defined") - 1)) {
525 zval t;
526
527 if (zend_optimizer_get_persistent_constant(Z_STR(ZEND_OP1_LITERAL(send1_opline)), &t, 0)) {
528
529 ZVAL_TRUE(&t);
530 if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_VAR, ZEND_RESULT(opline).var, &t)) {
531 literal_dtor(&ZEND_OP2_LITERAL(init_opline));
532 MAKE_NOP(init_opline);
533 literal_dtor(&ZEND_OP1_LITERAL(send1_opline));
534 MAKE_NOP(send1_opline);
535 MAKE_NOP(opline);
536 break;
537 }
538 }
539 } else if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("constant")-1 &&
540 !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)),
541 "constant", sizeof("constant")-1) &&
542 !zend_optimizer_is_disabled_func("constant", sizeof("constant") - 1)) {
543 zval t;
544
545 if (zend_optimizer_get_persistent_constant(Z_STR(ZEND_OP1_LITERAL(send1_opline)), &t, 1)) {
546 if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_VAR, ZEND_RESULT(opline).var, &t)) {
547 literal_dtor(&ZEND_OP2_LITERAL(init_opline));
548 MAKE_NOP(init_opline);
549 literal_dtor(&ZEND_OP1_LITERAL(send1_opline));
550 MAKE_NOP(send1_opline);
551 MAKE_NOP(opline);
552 break;
553 }
554 }
555 } else if ((CG(compiler_options) & ZEND_COMPILE_NO_BUILTIN_STRLEN) == 0 &&
556 Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("strlen") - 1 &&
557 !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)), "strlen", sizeof("strlen") - 1) &&
558 !zend_optimizer_is_disabled_func("strlen", sizeof("strlen") - 1)) {
559 zval t;
560
561 ZVAL_LONG(&t, Z_STRLEN(ZEND_OP1_LITERAL(send1_opline)));
562 if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_VAR, ZEND_RESULT(opline).var, &t)) {
563 literal_dtor(&ZEND_OP2_LITERAL(init_opline));
564 MAKE_NOP(init_opline);
565 literal_dtor(&ZEND_OP1_LITERAL(send1_opline));
566 MAKE_NOP(send1_opline);
567 MAKE_NOP(opline);
568 break;
569 }
570 /* dirname(IS_CONST/IS_STRING) -> IS_CONST/IS_STRING */
571 } else if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("dirname")-1 &&
572 !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)),
573 "dirname", sizeof("dirname") - 1) &&
574 !zend_optimizer_is_disabled_func("dirname", sizeof("dirname") - 1) &&
575 IS_ABSOLUTE_PATH(Z_STRVAL(ZEND_OP1_LITERAL(send1_opline)), Z_STRLEN(ZEND_OP1_LITERAL(send1_opline)))) {
576 zend_string *dirname = zend_string_init(Z_STRVAL(ZEND_OP1_LITERAL(send1_opline)), Z_STRLEN(ZEND_OP1_LITERAL(send1_opline)), 0);
577 ZSTR_LEN(dirname) = zend_dirname(ZSTR_VAL(dirname), ZSTR_LEN(dirname));
578 if (IS_ABSOLUTE_PATH(ZSTR_VAL(dirname), ZSTR_LEN(dirname))) {
579 zval t;
580
581 ZVAL_STR(&t, dirname);
582 if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_VAR, ZEND_RESULT(opline).var, &t)) {
583 literal_dtor(&ZEND_OP2_LITERAL(init_opline));
584 MAKE_NOP(init_opline);
585 literal_dtor(&ZEND_OP1_LITERAL(send1_opline));
586 MAKE_NOP(send1_opline);
587 MAKE_NOP(opline);
588 break;
589 }
590 } else {
591 zend_string_release(dirname);
592 }
593 }
594 }
595 /* don't colllect constants after any other function call */
596 collect_constants = 0;
597 break;
598 }
599 case ZEND_STRLEN:
600 if (ZEND_OP1_TYPE(opline) == IS_CONST &&
601 Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING) {
602 zval t;
603
604 ZVAL_LONG(&t, Z_STRLEN(ZEND_OP1_LITERAL(opline)));
605 if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_TMP_VAR, ZEND_RESULT(opline).var, &t)) {
606 literal_dtor(&ZEND_OP1_LITERAL(opline));
607 MAKE_NOP(opline);
608 }
609 }
610 break;
611 case ZEND_DEFINED:
612 {
613 zval c;
614 uint32_t tv = ZEND_RESULT(opline).var;
615 if (!zend_optimizer_get_persistent_constant(Z_STR(ZEND_OP1_LITERAL(opline)), &c, 0)) {
616 break;
617 }
618 ZVAL_TRUE(&c);
619 if (zend_optimizer_replace_by_const(op_array, opline, IS_TMP_VAR, tv, &c)) {
620 literal_dtor(&ZEND_OP1_LITERAL(opline));
621 MAKE_NOP(opline);
622 }
623 }
624 break;
625 case ZEND_DECLARE_CONST:
626 if (collect_constants &&
627 Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING &&
628 Z_TYPE(ZEND_OP2_LITERAL(opline)) <= IS_STRING) {
629 zend_optimizer_collect_constant(ctx, &ZEND_OP1_LITERAL(opline), &ZEND_OP2_LITERAL(opline));
630 }
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_CATCH:
639 case ZEND_FAST_CALL:
640 case ZEND_FAST_RET:
641 case ZEND_JMP:
642 case ZEND_JMPZNZ:
643 case ZEND_JMPZ:
644 case ZEND_JMPNZ:
645 case ZEND_JMPZ_EX:
646 case ZEND_JMPNZ_EX:
647 case ZEND_FE_RESET_R:
648 case ZEND_FE_RESET_RW:
649 case ZEND_FE_FETCH_R:
650 case ZEND_FE_FETCH_RW:
651 case ZEND_JMP_SET:
652 case ZEND_COALESCE:
653 case ZEND_ASSERT_CHECK:
654 collect_constants = 0;
655 break;
656 }
657 opline++;
658 i++;
659 }
660 }
661