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