1 /*
2 +----------------------------------------------------------------------+
3 | Zend OPcache |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1998-2017 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 & 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 }
88 er = EG(error_reporting);
89 EG(error_reporting) = 0;
90 /* evaluate constant expression */
91 if (binary_op(&result, &ZEND_OP1_LITERAL(opline), &ZEND_OP2_LITERAL(opline)) != SUCCESS) {
92 EG(error_reporting) = er;
93 break;
94 }
95 EG(error_reporting) = er;
96
97 if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_TMP_VAR, tv, &result)) {
98 literal_dtor(&ZEND_OP1_LITERAL(opline));
99 literal_dtor(&ZEND_OP2_LITERAL(opline));
100 MAKE_NOP(opline);
101 }
102 }
103 break;
104
105 case ZEND_CAST:
106 if (ZEND_OP1_TYPE(opline) == IS_CONST &&
107 opline->extended_value != IS_ARRAY &&
108 opline->extended_value != IS_OBJECT &&
109 opline->extended_value != IS_RESOURCE &&
110 (opline->extended_value != IS_STRING
111 || Z_TYPE(ZEND_OP1_LITERAL(opline)) != IS_ARRAY)) {
112 /* cast of constant operand */
113 zend_uchar type = opline->result_type;
114 uint32_t tv = ZEND_RESULT(opline).var; /* temporary variable */
115 zval res;
116 res = ZEND_OP1_LITERAL(opline);
117 zval_copy_ctor(&res);
118 switch (opline->extended_value) {
119 case IS_NULL:
120 convert_to_null(&res);
121 break;
122 case _IS_BOOL:
123 convert_to_boolean(&res);
124 break;
125 case IS_LONG:
126 convert_to_long(&res);
127 break;
128 case IS_DOUBLE:
129 convert_to_double(&res);
130 break;
131 case IS_STRING:
132 convert_to_string(&res);
133 break;
134 }
135
136 if (zend_optimizer_replace_by_const(op_array, opline + 1, type, tv, &res)) {
137 literal_dtor(&ZEND_OP1_LITERAL(opline));
138 MAKE_NOP(opline);
139 }
140 } else if (opline->extended_value == _IS_BOOL) {
141 /* T = CAST(X, IS_BOOL) => T = BOOL(X) */
142 opline->opcode = ZEND_BOOL;
143 opline->extended_value = 0;
144 }
145 break;
146
147 case ZEND_BW_NOT:
148 case ZEND_BOOL_NOT:
149 if (ZEND_OP1_TYPE(opline) == IS_CONST) {
150 /* unary operation on constant operand */
151 unary_op_type unary_op = get_unary_op(opline->opcode);
152 zval result;
153 uint32_t tv = ZEND_RESULT(opline).var; /* temporary variable */
154 int er;
155
156 er = EG(error_reporting);
157 EG(error_reporting) = 0;
158 if (unary_op(&result, &ZEND_OP1_LITERAL(opline)) != SUCCESS) {
159 EG(error_reporting) = er;
160 break;
161 }
162 EG(error_reporting) = er;
163
164 if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_TMP_VAR, tv, &result)) {
165 literal_dtor(&ZEND_OP1_LITERAL(opline));
166 MAKE_NOP(opline);
167 }
168 }
169 break;
170
171 #if 0
172 case ZEND_ADD_STRING:
173 case ZEND_ADD_CHAR:
174 {
175 zend_op *next_op = opline + 1;
176 int requires_conversion = (opline->opcode == ZEND_ADD_CHAR? 1 : 0);
177 size_t final_length = 0;
178 zend_string *str;
179 char *ptr;
180 zend_op *last_op;
181
182 /* There is always a ZEND_RETURN at the end
183 if (next_op>=end) {
184 break;
185 }
186 */
187 while (next_op->opcode == ZEND_ADD_STRING || next_op->opcode == ZEND_ADD_CHAR) {
188 if (ZEND_RESULT(opline).var != ZEND_RESULT(next_op).var) {
189 break;
190 }
191 if (next_op->opcode == ZEND_ADD_CHAR) {
192 final_length += 1;
193 } else { /* ZEND_ADD_STRING */
194 final_length += Z_STRLEN(ZEND_OP2_LITERAL(next_op));
195 }
196 next_op++;
197 }
198 if (final_length == 0) {
199 break;
200 }
201 last_op = next_op;
202 final_length += (requires_conversion? 1 : Z_STRLEN(ZEND_OP2_LITERAL(opline)));
203 str = zend_string_alloc(final_length, 0);
204 str->len = final_length;
205 ptr = str->val;
206 ptr[final_length] = '\0';
207 if (requires_conversion) { /* ZEND_ADD_CHAR */
208 char chval = (char)Z_LVAL(ZEND_OP2_LITERAL(opline));
209
210 ZVAL_NEW_STR(&ZEND_OP2_LITERAL(opline), str);
211 ptr[0] = chval;
212 opline->opcode = ZEND_ADD_STRING;
213 ptr++;
214 } else { /* ZEND_ADD_STRING */
215 memcpy(ptr, Z_STRVAL(ZEND_OP2_LITERAL(opline)), Z_STRLEN(ZEND_OP2_LITERAL(opline)));
216 ptr += Z_STRLEN(ZEND_OP2_LITERAL(opline));
217 zend_string_release(Z_STR(ZEND_OP2_LITERAL(opline)));
218 ZVAL_NEW_STR(&ZEND_OP2_LITERAL(opline), str);
219 }
220 next_op = opline + 1;
221 while (next_op < last_op) {
222 if (next_op->opcode == ZEND_ADD_STRING) {
223 memcpy(ptr, Z_STRVAL(ZEND_OP2_LITERAL(next_op)), Z_STRLEN(ZEND_OP2_LITERAL(next_op)));
224 ptr += Z_STRLEN(ZEND_OP2_LITERAL(next_op));
225 literal_dtor(&ZEND_OP2_LITERAL(next_op));
226 } else { /* ZEND_ADD_CHAR */
227 *ptr = (char)Z_LVAL(ZEND_OP2_LITERAL(next_op));
228 ptr++;
229 }
230 MAKE_NOP(next_op);
231 next_op++;
232 }
233 if (!((ZEND_OPTIMIZER_PASS_5|ZEND_OPTIMIZER_PASS_10) & OPTIMIZATION_LEVEL)) {
234 /* NOP removal is disabled => insert JMP over NOPs */
235 if (last_op-opline >= 3) { /* If we have more than 2 NOPS then JMP over them */
236 (opline + 1)->opcode = ZEND_JMP;
237 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 */
238 }
239 }
240 }
241 break;
242 #endif
243
244 case ZEND_FETCH_CONSTANT:
245 if (ZEND_OP1_TYPE(opline) == IS_UNUSED &&
246 ZEND_OP2_TYPE(opline) == IS_CONST &&
247 Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING &&
248 Z_STRLEN(ZEND_OP2_LITERAL(opline)) == sizeof("__COMPILER_HALT_OFFSET__") - 1 &&
249 memcmp(Z_STRVAL(ZEND_OP2_LITERAL(opline)), "__COMPILER_HALT_OFFSET__", sizeof("__COMPILER_HALT_OFFSET__") - 1) == 0) {
250 /* substitute __COMPILER_HALT_OFFSET__ constant */
251 zend_execute_data *orig_execute_data = EG(current_execute_data);
252 zend_execute_data fake_execute_data;
253 zval *offset;
254
255 memset(&fake_execute_data, 0, sizeof(zend_execute_data));
256 fake_execute_data.func = (zend_function*)op_array;
257 EG(current_execute_data) = &fake_execute_data;
258 if ((offset = zend_get_constant_str("__COMPILER_HALT_OFFSET__", sizeof("__COMPILER_HALT_OFFSET__") - 1)) != NULL) {
259 uint32_t tv = ZEND_RESULT(opline).var;
260
261 if (zend_optimizer_replace_by_const(op_array, opline, IS_TMP_VAR, tv, offset)) {
262 literal_dtor(&ZEND_OP2_LITERAL(opline));
263 MAKE_NOP(opline);
264 }
265 }
266 EG(current_execute_data) = orig_execute_data;
267 break;
268 }
269
270 if (ZEND_OP1_TYPE(opline) == IS_UNUSED &&
271 ZEND_OP2_TYPE(opline) == IS_CONST &&
272 Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING) {
273 /* substitute persistent constants */
274 uint32_t tv = ZEND_RESULT(opline).var;
275 zval c;
276
277 if (!zend_optimizer_get_persistent_constant(Z_STR(ZEND_OP2_LITERAL(opline)), &c, 1)) {
278 if (!ctx->constants || !zend_optimizer_get_collected_constant(ctx->constants, &ZEND_OP2_LITERAL(opline), &c)) {
279 break;
280 }
281 }
282 if (Z_TYPE(c) == IS_CONSTANT_AST) {
283 break;
284 }
285 if (zend_optimizer_replace_by_const(op_array, opline, IS_TMP_VAR, tv, &c)) {
286 literal_dtor(&ZEND_OP2_LITERAL(opline));
287 MAKE_NOP(opline);
288 }
289 }
290
291 /* class constant */
292 if (ZEND_OP1_TYPE(opline) != IS_UNUSED &&
293 ZEND_OP2_TYPE(opline) == IS_CONST &&
294 Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING) {
295
296 zend_class_entry *ce = NULL;
297
298 if (ZEND_OP1_TYPE(opline) == IS_CONST &&
299 Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING) {
300 /* for A::B */
301 if (op_array->scope &&
302 !strncasecmp(Z_STRVAL(ZEND_OP1_LITERAL(opline)),
303 ZSTR_VAL(op_array->scope->name), Z_STRLEN(ZEND_OP1_LITERAL(opline)) + 1)) {
304 ce = op_array->scope;
305 } else {
306 if ((ce = zend_hash_find_ptr(EG(class_table),
307 Z_STR(op_array->literals[opline->op1.constant + 1]))) == NULL ||
308 (ce->type == ZEND_INTERNAL_CLASS &&
309 ce->info.internal.module->type != MODULE_PERSISTENT) ||
310 (ce->type == ZEND_USER_CLASS &&
311 ZEND_CE_FILENAME(ce) != op_array->filename)) {
312 break;
313 }
314 }
315 } else if (op_array->scope &&
316 ZEND_OP1_TYPE(opline) == IS_VAR &&
317 (opline - 1)->opcode == ZEND_FETCH_CLASS &&
318 (ZEND_OP1_TYPE(opline - 1) == IS_UNUSED &&
319 ((opline - 1)->extended_value & ~ZEND_FETCH_CLASS_NO_AUTOLOAD) == ZEND_FETCH_CLASS_SELF) &&
320 ZEND_RESULT((opline - 1)).var == ZEND_OP1(opline).var) {
321 /* for self::B */
322 ce = op_array->scope;
323 }
324
325 if (ce) {
326 uint32_t tv = ZEND_RESULT(opline).var;
327 zval *c, t;
328
329 if ((c = zend_hash_find(&ce->constants_table,
330 Z_STR(ZEND_OP2_LITERAL(opline)))) != NULL) {
331 ZVAL_DEREF(c);
332 if (Z_TYPE_P(c) == IS_CONSTANT_AST) {
333 break;
334 }
335 if (ZEND_IS_CONSTANT_TYPE(Z_TYPE_P(c))) {
336 if (!zend_optimizer_get_persistent_constant(Z_STR_P(c), &t, 1) ||
337 ZEND_IS_CONSTANT_TYPE(Z_TYPE(t))) {
338 break;
339 }
340 } else {
341 ZVAL_COPY_VALUE(&t, c);
342 zval_copy_ctor(&t);
343 }
344
345 if (ZEND_OP1_TYPE(opline) == IS_CONST) {
346 literal_dtor(&ZEND_OP1_LITERAL(opline));
347 } else {
348 MAKE_NOP((opline - 1));
349 }
350 if (zend_optimizer_replace_by_const(op_array, opline, IS_TMP_VAR, tv, &t)) {
351 literal_dtor(&ZEND_OP2_LITERAL(opline));
352 MAKE_NOP(opline);
353 }
354 }
355 }
356 }
357 break;
358
359 case ZEND_DO_ICALL: {
360 zend_op *send1_opline = opline - 1;
361 zend_op *send2_opline = NULL;
362 zend_op *init_opline = NULL;
363
364 while (send1_opline->opcode == ZEND_NOP) {
365 send1_opline--;
366 }
367 if (send1_opline->opcode != ZEND_SEND_VAL ||
368 ZEND_OP1_TYPE(send1_opline) != IS_CONST) {
369 /* don't colllect constants after unknown function call */
370 collect_constants = 0;
371 break;
372 }
373 if (send1_opline->op2.num == 2) {
374 send2_opline = send1_opline;
375 send1_opline--;
376 while (send1_opline->opcode == ZEND_NOP) {
377 send1_opline--;
378 }
379 if (send1_opline->opcode != ZEND_SEND_VAL ||
380 ZEND_OP1_TYPE(send1_opline) != IS_CONST) {
381 /* don't colllect constants after unknown function call */
382 collect_constants = 0;
383 break;
384 }
385 }
386 init_opline = send1_opline - 1;
387 while (init_opline->opcode == ZEND_NOP) {
388 init_opline--;
389 }
390 if (init_opline->opcode != ZEND_INIT_FCALL ||
391 ZEND_OP2_TYPE(init_opline) != IS_CONST ||
392 Z_TYPE(ZEND_OP2_LITERAL(init_opline)) != IS_STRING) {
393 /* don't colllect constants after unknown function call */
394 collect_constants = 0;
395 break;
396 }
397
398 /* define("name", scalar); */
399 if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("define")-1 &&
400 zend_binary_strcasecmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)), Z_STRLEN(ZEND_OP2_LITERAL(init_opline)), "define", sizeof("define")-1) == 0) {
401
402 if (Z_TYPE(ZEND_OP1_LITERAL(send1_opline)) == IS_STRING &&
403 send2_opline &&
404 Z_TYPE(ZEND_OP1_LITERAL(send2_opline)) <= IS_STRING) {
405
406 if (collect_constants) {
407 zend_optimizer_collect_constant(ctx, &ZEND_OP1_LITERAL(send1_opline), &ZEND_OP1_LITERAL(send2_opline));
408 }
409
410 if (RESULT_UNUSED(opline) &&
411 !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)))) {
412
413 opline->opcode = ZEND_DECLARE_CONST;
414 opline->op1_type = IS_CONST;
415 opline->op2_type = IS_CONST;
416 opline->result_type = IS_UNUSED;
417 opline->op1.constant = send1_opline->op1.constant;
418 opline->op2.constant = send2_opline->op1.constant;
419 opline->result.num = 0;
420
421 literal_dtor(&ZEND_OP2_LITERAL(init_opline));
422 MAKE_NOP(init_opline);
423 MAKE_NOP(send1_opline);
424 MAKE_NOP(send2_opline);
425 }
426 break;
427 }
428 }
429
430 /* pre-evaluate constant functions:
431 defined(x)
432 constant(x)
433 function_exists(x)
434 is_callable(x)
435 extension_loaded(x)
436 */
437 if (!send2_opline &&
438 Z_TYPE(ZEND_OP1_LITERAL(send1_opline)) == IS_STRING) {
439 if ((Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("function_exists")-1 &&
440 !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)),
441 "function_exists", sizeof("function_exists")-1) &&
442 !zend_optimizer_is_disabled_func("function_exists", sizeof("function_exists") - 1)) ||
443 (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("is_callable")-1 &&
444 !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)),
445 "is_callable", sizeof("is_callable")) &&
446 !zend_optimizer_is_disabled_func("is_callable", sizeof("is_callable") - 1))) {
447 zend_internal_function *func;
448 zend_string *lc_name = zend_string_tolower(
449 Z_STR(ZEND_OP1_LITERAL(send1_opline)));
450
451 if ((func = zend_hash_find_ptr(EG(function_table), lc_name)) != NULL
452 && func->type == ZEND_INTERNAL_FUNCTION
453 && func->module->type == MODULE_PERSISTENT
454 #ifdef ZEND_WIN32
455 && func->module->handle == NULL
456 #endif
457 ) {
458 zval t;
459 if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("is_callable") - 1 ||
460 func->handler != ZEND_FN(display_disabled_function)) {
461 ZVAL_TRUE(&t);
462 } else {
463 ZVAL_FALSE(&t);
464 }
465 if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_VAR, ZEND_RESULT(opline).var, &t)) {
466 literal_dtor(&ZEND_OP2_LITERAL(init_opline));
467 MAKE_NOP(init_opline);
468 literal_dtor(&ZEND_OP1_LITERAL(send1_opline));
469 MAKE_NOP(send1_opline);
470 MAKE_NOP(opline);
471 zend_string_release(lc_name);
472 break;
473 }
474 }
475 zend_string_release(lc_name);
476 } else if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("extension_loaded")-1 &&
477 !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)),
478 "extension_loaded", sizeof("extension_loaded")-1) &&
479 !zend_optimizer_is_disabled_func("extension_loaded", sizeof("extension_loaded") - 1)) {
480 zval t;
481 zend_string *lc_name = zend_string_tolower(
482 Z_STR(ZEND_OP1_LITERAL(send1_opline)));
483 zend_module_entry *m = zend_hash_find_ptr(&module_registry,
484 lc_name);
485
486 zend_string_release(lc_name);
487 if (!m) {
488 if (PG(enable_dl)) {
489 break;
490 } else {
491 ZVAL_FALSE(&t);
492 }
493 } else {
494 if (m->type == MODULE_PERSISTENT
495 #ifdef ZEND_WIN32
496 && m->handle == NULL
497 #endif
498 ) {
499 ZVAL_TRUE(&t);
500 } else {
501 break;
502 }
503 }
504
505 if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_VAR, ZEND_RESULT(opline).var, &t)) {
506 literal_dtor(&ZEND_OP2_LITERAL(init_opline));
507 MAKE_NOP(init_opline);
508 literal_dtor(&ZEND_OP1_LITERAL(send1_opline));
509 MAKE_NOP(send1_opline);
510 MAKE_NOP(opline);
511 break;
512 }
513 } else if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("defined")-1 &&
514 !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)),
515 "defined", sizeof("defined")-1) &&
516 !zend_optimizer_is_disabled_func("defined", sizeof("defined") - 1)) {
517 zval t;
518
519 if (zend_optimizer_get_persistent_constant(Z_STR(ZEND_OP1_LITERAL(send1_opline)), &t, 0)) {
520
521 ZVAL_TRUE(&t);
522 if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_VAR, ZEND_RESULT(opline).var, &t)) {
523 literal_dtor(&ZEND_OP2_LITERAL(init_opline));
524 MAKE_NOP(init_opline);
525 literal_dtor(&ZEND_OP1_LITERAL(send1_opline));
526 MAKE_NOP(send1_opline);
527 MAKE_NOP(opline);
528 break;
529 }
530 }
531 } else if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("constant")-1 &&
532 !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)),
533 "constant", sizeof("constant")-1) &&
534 !zend_optimizer_is_disabled_func("constant", sizeof("constant") - 1)) {
535 zval t;
536
537 if (zend_optimizer_get_persistent_constant(Z_STR(ZEND_OP1_LITERAL(send1_opline)), &t, 1)) {
538 if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_VAR, ZEND_RESULT(opline).var, &t)) {
539 literal_dtor(&ZEND_OP2_LITERAL(init_opline));
540 MAKE_NOP(init_opline);
541 literal_dtor(&ZEND_OP1_LITERAL(send1_opline));
542 MAKE_NOP(send1_opline);
543 MAKE_NOP(opline);
544 break;
545 }
546 }
547 } else if ((CG(compiler_options) & ZEND_COMPILE_NO_BUILTIN_STRLEN) == 0 &&
548 Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("strlen") - 1 &&
549 !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)), "strlen", sizeof("strlen") - 1) &&
550 !zend_optimizer_is_disabled_func("strlen", sizeof("strlen") - 1)) {
551 zval t;
552
553 ZVAL_LONG(&t, Z_STRLEN(ZEND_OP1_LITERAL(send1_opline)));
554 if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_VAR, ZEND_RESULT(opline).var, &t)) {
555 literal_dtor(&ZEND_OP2_LITERAL(init_opline));
556 MAKE_NOP(init_opline);
557 literal_dtor(&ZEND_OP1_LITERAL(send1_opline));
558 MAKE_NOP(send1_opline);
559 MAKE_NOP(opline);
560 break;
561 }
562 /* dirname(IS_CONST/IS_STRING) -> IS_CONST/IS_STRING */
563 } else if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("dirname")-1 &&
564 !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)),
565 "dirname", sizeof("dirname") - 1) &&
566 !zend_optimizer_is_disabled_func("dirname", sizeof("dirname") - 1) &&
567 IS_ABSOLUTE_PATH(Z_STRVAL(ZEND_OP1_LITERAL(send1_opline)), Z_STRLEN(ZEND_OP1_LITERAL(send1_opline)))) {
568 zend_string *dirname = zend_string_init(Z_STRVAL(ZEND_OP1_LITERAL(send1_opline)), Z_STRLEN(ZEND_OP1_LITERAL(send1_opline)), 0);
569 ZSTR_LEN(dirname) = zend_dirname(ZSTR_VAL(dirname), ZSTR_LEN(dirname));
570 if (IS_ABSOLUTE_PATH(ZSTR_VAL(dirname), ZSTR_LEN(dirname))) {
571 zval t;
572
573 ZVAL_STR(&t, dirname);
574 if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_VAR, ZEND_RESULT(opline).var, &t)) {
575 literal_dtor(&ZEND_OP2_LITERAL(init_opline));
576 MAKE_NOP(init_opline);
577 literal_dtor(&ZEND_OP1_LITERAL(send1_opline));
578 MAKE_NOP(send1_opline);
579 MAKE_NOP(opline);
580 break;
581 }
582 } else {
583 zend_string_release(dirname);
584 }
585 }
586 }
587 /* don't colllect constants after any other function call */
588 collect_constants = 0;
589 break;
590 }
591 case ZEND_STRLEN:
592 if (ZEND_OP1_TYPE(opline) == IS_CONST &&
593 Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING) {
594 zval t;
595
596 ZVAL_LONG(&t, Z_STRLEN(ZEND_OP1_LITERAL(opline)));
597 if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_TMP_VAR, ZEND_RESULT(opline).var, &t)) {
598 literal_dtor(&ZEND_OP1_LITERAL(opline));
599 MAKE_NOP(opline);
600 }
601 }
602 break;
603 case ZEND_DEFINED:
604 {
605 zval c;
606 uint32_t tv = ZEND_RESULT(opline).var;
607 if (!zend_optimizer_get_persistent_constant(Z_STR(ZEND_OP1_LITERAL(opline)), &c, 0)) {
608 break;
609 }
610 ZVAL_TRUE(&c);
611 if (zend_optimizer_replace_by_const(op_array, opline, IS_TMP_VAR, tv, &c)) {
612 literal_dtor(&ZEND_OP1_LITERAL(opline));
613 MAKE_NOP(opline);
614 }
615 }
616 break;
617 case ZEND_DECLARE_CONST:
618 if (collect_constants &&
619 Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING &&
620 Z_TYPE(ZEND_OP2_LITERAL(opline)) <= IS_STRING) {
621 zend_optimizer_collect_constant(ctx, &ZEND_OP1_LITERAL(opline), &ZEND_OP2_LITERAL(opline));
622 }
623 break;
624
625 case ZEND_RETURN:
626 case ZEND_RETURN_BY_REF:
627 case ZEND_GENERATOR_RETURN:
628 case ZEND_EXIT:
629 case ZEND_THROW:
630 case ZEND_CATCH:
631 case ZEND_FAST_CALL:
632 case ZEND_FAST_RET:
633 case ZEND_JMP:
634 case ZEND_JMPZNZ:
635 case ZEND_JMPZ:
636 case ZEND_JMPNZ:
637 case ZEND_JMPZ_EX:
638 case ZEND_JMPNZ_EX:
639 case ZEND_FE_RESET_R:
640 case ZEND_FE_RESET_RW:
641 case ZEND_FE_FETCH_R:
642 case ZEND_FE_FETCH_RW:
643 case ZEND_NEW:
644 case ZEND_JMP_SET:
645 case ZEND_COALESCE:
646 case ZEND_ASSERT_CHECK:
647 collect_constants = 0;
648 break;
649 case ZEND_FETCH_R:
650 case ZEND_FETCH_W:
651 case ZEND_FETCH_RW:
652 case ZEND_FETCH_FUNC_ARG:
653 case ZEND_FETCH_IS:
654 case ZEND_FETCH_UNSET:
655 if (opline != op_array->opcodes &&
656 (opline-1)->opcode == ZEND_BEGIN_SILENCE &&
657 (opline->extended_value & ZEND_FETCH_TYPE_MASK) == ZEND_FETCH_LOCAL &&
658 opline->op1_type == IS_CONST &&
659 opline->op2_type == IS_UNUSED &&
660 Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING &&
661 (Z_STRLEN(ZEND_OP1_LITERAL(opline)) != sizeof("this")-1 ||
662 memcmp(Z_STRVAL(ZEND_OP1_LITERAL(opline)), "this", sizeof("this") - 1) != 0)) {
663
664 int var = opline->result.var;
665 int level = 0;
666 zend_op *op = opline + 1;
667 zend_op *use = NULL;
668
669 while (op < end) {
670 if (op->opcode == ZEND_BEGIN_SILENCE) {
671 level++;
672 } else if (op->opcode == ZEND_END_SILENCE) {
673 if (level == 0) {
674 break;
675 } else {
676 level--;
677 }
678 }
679 if (op->op1_type == IS_VAR && op->op1.var == var) {
680 if (use) {
681 /* used more than once */
682 use = NULL;
683 break;
684 }
685 use = op;
686 } else if (op->op2_type == IS_VAR && op->op2.var == var) {
687 if (use) {
688 /* used more than once */
689 use = NULL;
690 break;
691 }
692 use = op;
693 }
694 op++;
695 }
696 if (use) {
697 if (use->op1_type == IS_VAR && use->op1.var == var) {
698 use->op1_type = IS_CV;
699 use->op1.var = zend_optimizer_lookup_cv(op_array,
700 Z_STR(ZEND_OP1_LITERAL(opline)));
701 MAKE_NOP(opline);
702 } else if (use->op2_type == IS_VAR && use->op2.var == var) {
703 use->op2_type = IS_CV;
704 use->op2.var = zend_optimizer_lookup_cv(op_array,
705 Z_STR(ZEND_OP1_LITERAL(opline)));
706 MAKE_NOP(opline);
707 }
708 }
709 }
710 break;
711 }
712 opline++;
713 i++;
714 }
715 }
716