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 case ZEND_CASE:
72 if (opline->op1_type == IS_CONST &&
73 opline->op2_type == IS_CONST) {
74 /* binary operation with constant operands */
75 zval result;
76
77 if (zend_optimizer_eval_binary_op(&result, opline->opcode, &ZEND_OP1_LITERAL(opline), &ZEND_OP2_LITERAL(opline)) == SUCCESS) {
78 literal_dtor(&ZEND_OP1_LITERAL(opline));
79 literal_dtor(&ZEND_OP2_LITERAL(opline));
80 if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_TMP_VAR, opline->result.var, &result)) {
81 MAKE_NOP(opline);
82 } else {
83 opline->opcode = ZEND_QM_ASSIGN;
84 SET_UNUSED(opline->op2);
85 zend_optimizer_update_op1_const(op_array, opline, &result);
86 }
87 }
88 }
89 break;
90
91 case ZEND_CAST:
92 if (opline->op1_type == IS_CONST) {
93 /* cast of constant operand */
94 zval result;
95
96 if (zend_optimizer_eval_cast(&result, opline->extended_value, &ZEND_OP1_LITERAL(opline)) == SUCCESS) {
97 literal_dtor(&ZEND_OP1_LITERAL(opline));
98 if (zend_optimizer_replace_by_const(op_array, opline + 1, opline->result_type, opline->result.var, &result)) {
99 MAKE_NOP(opline);
100 } else {
101 opline->opcode = ZEND_QM_ASSIGN;
102 opline->extended_value = 0;
103 zend_optimizer_update_op1_const(op_array, opline, &result);
104 }
105 break;
106 }
107 }
108
109 if (opline->extended_value == _IS_BOOL) {
110 /* T = CAST(X, IS_BOOL) => T = BOOL(X) */
111 opline->opcode = ZEND_BOOL;
112 opline->extended_value = 0;
113 }
114 break;
115
116 case ZEND_BW_NOT:
117 case ZEND_BOOL_NOT:
118 if (opline->op1_type == IS_CONST) {
119 /* unary operation on constant operand */
120 zval result;
121
122 if (zend_optimizer_eval_unary_op(&result, opline->opcode, &ZEND_OP1_LITERAL(opline)) == SUCCESS) {
123 literal_dtor(&ZEND_OP1_LITERAL(opline));
124 if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_TMP_VAR, opline->result.var, &result)) {
125 MAKE_NOP(opline);
126 } else {
127 opline->opcode = ZEND_QM_ASSIGN;
128 zend_optimizer_update_op1_const(op_array, opline, &result);
129 }
130 }
131 }
132 break;
133
134 #if 0
135 case ZEND_ADD_STRING:
136 case ZEND_ADD_CHAR:
137 {
138 zend_op *next_op = opline + 1;
139 int requires_conversion = (opline->opcode == ZEND_ADD_CHAR? 1 : 0);
140 size_t final_length = 0;
141 zend_string *str;
142 char *ptr;
143 zend_op *last_op;
144
145 /* There is always a ZEND_RETURN at the end
146 if (next_op>=end) {
147 break;
148 }
149 */
150 while (next_op->opcode == ZEND_ADD_STRING || next_op->opcode == ZEND_ADD_CHAR) {
151 if (opline->result.var != next_op->result.var) {
152 break;
153 }
154 if (next_op->opcode == ZEND_ADD_CHAR) {
155 final_length += 1;
156 } else { /* ZEND_ADD_STRING */
157 final_length += Z_STRLEN(ZEND_OP2_LITERAL(next_op));
158 }
159 next_op++;
160 }
161 if (final_length == 0) {
162 break;
163 }
164 last_op = next_op;
165 final_length += (requires_conversion? 1 : Z_STRLEN(ZEND_OP2_LITERAL(opline)));
166 str = zend_string_alloc(final_length, 0);
167 str->len = final_length;
168 ptr = str->val;
169 ptr[final_length] = '\0';
170 if (requires_conversion) { /* ZEND_ADD_CHAR */
171 char chval = (char)Z_LVAL(ZEND_OP2_LITERAL(opline));
172
173 ZVAL_NEW_STR(&ZEND_OP2_LITERAL(opline), str);
174 ptr[0] = chval;
175 opline->opcode = ZEND_ADD_STRING;
176 ptr++;
177 } else { /* ZEND_ADD_STRING */
178 memcpy(ptr, Z_STRVAL(ZEND_OP2_LITERAL(opline)), Z_STRLEN(ZEND_OP2_LITERAL(opline)));
179 ptr += Z_STRLEN(ZEND_OP2_LITERAL(opline));
180 zend_string_release(Z_STR(ZEND_OP2_LITERAL(opline)));
181 ZVAL_NEW_STR(&ZEND_OP2_LITERAL(opline), str);
182 }
183 next_op = opline + 1;
184 while (next_op < last_op) {
185 if (next_op->opcode == ZEND_ADD_STRING) {
186 memcpy(ptr, Z_STRVAL(ZEND_OP2_LITERAL(next_op)), Z_STRLEN(ZEND_OP2_LITERAL(next_op)));
187 ptr += Z_STRLEN(ZEND_OP2_LITERAL(next_op));
188 literal_dtor(&ZEND_OP2_LITERAL(next_op));
189 } else { /* ZEND_ADD_CHAR */
190 *ptr = (char)Z_LVAL(ZEND_OP2_LITERAL(next_op));
191 ptr++;
192 }
193 MAKE_NOP(next_op);
194 next_op++;
195 }
196 if (!((ZEND_OPTIMIZER_PASS_5|ZEND_OPTIMIZER_PASS_10) & OPTIMIZATION_LEVEL)) {
197 /* NOP removal is disabled => insert JMP over NOPs */
198 if (last_op-opline >= 3) { /* If we have more than 2 NOPS then JMP over them */
199 (opline + 1)->opcode = ZEND_JMP;
200 (opline + 1)->op1.opline_num = last_op - op_array->opcodes; /* that's OK even for ZE2, since opline_num's are resolved in pass 2 later */
201 }
202 }
203 }
204 break;
205 #endif
206
207 case ZEND_FETCH_CONSTANT:
208 if (opline->op2_type == IS_CONST &&
209 Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING &&
210 Z_STRLEN(ZEND_OP2_LITERAL(opline)) == sizeof("__COMPILER_HALT_OFFSET__") - 1 &&
211 memcmp(Z_STRVAL(ZEND_OP2_LITERAL(opline)), "__COMPILER_HALT_OFFSET__", sizeof("__COMPILER_HALT_OFFSET__") - 1) == 0) {
212 /* substitute __COMPILER_HALT_OFFSET__ constant */
213 zend_execute_data *orig_execute_data = EG(current_execute_data);
214 zend_execute_data fake_execute_data;
215 zval *offset;
216
217 memset(&fake_execute_data, 0, sizeof(zend_execute_data));
218 fake_execute_data.func = (zend_function*)op_array;
219 EG(current_execute_data) = &fake_execute_data;
220 if ((offset = zend_get_constant_str("__COMPILER_HALT_OFFSET__", sizeof("__COMPILER_HALT_OFFSET__") - 1)) != NULL) {
221
222 literal_dtor(&ZEND_OP2_LITERAL(opline));
223 if (zend_optimizer_replace_by_const(op_array, opline, IS_TMP_VAR, opline->result.var, offset)) {
224 MAKE_NOP(opline);
225 } else {
226 opline->opcode = ZEND_QM_ASSIGN;
227 opline->extended_value = 0;
228 SET_UNUSED(opline->op2);
229 zend_optimizer_update_op1_const(op_array, opline, offset);
230 }
231 }
232 EG(current_execute_data) = orig_execute_data;
233 break;
234 }
235
236 if (opline->op2_type == IS_CONST &&
237 Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING) {
238 /* substitute persistent constants */
239 zval c;
240
241 if (!zend_optimizer_get_persistent_constant(Z_STR(ZEND_OP2_LITERAL(opline)), &c, 1)) {
242 if (!ctx->constants || !zend_optimizer_get_collected_constant(ctx->constants, &ZEND_OP2_LITERAL(opline), &c)) {
243 break;
244 }
245 }
246 if (Z_TYPE(c) == IS_CONSTANT_AST) {
247 break;
248 }
249 literal_dtor(&ZEND_OP2_LITERAL(opline));
250 if (zend_optimizer_replace_by_const(op_array, opline, IS_TMP_VAR, opline->result.var, &c)) {
251 MAKE_NOP(opline);
252 } else {
253 opline->opcode = ZEND_QM_ASSIGN;
254 opline->extended_value = 0;
255 SET_UNUSED(opline->op2);
256 zend_optimizer_update_op1_const(op_array, opline, &c);
257 }
258 }
259 break;
260
261 case ZEND_FETCH_CLASS_CONSTANT:
262 if (opline->op2_type == IS_CONST &&
263 Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING) {
264
265 zend_class_entry *ce = NULL;
266
267 if (opline->op1_type == IS_CONST &&
268 Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING) {
269 /* for A::B */
270 if (op_array->scope &&
271 !strncasecmp(Z_STRVAL(ZEND_OP1_LITERAL(opline)),
272 ZSTR_VAL(op_array->scope->name), Z_STRLEN(ZEND_OP1_LITERAL(opline)) + 1)) {
273 ce = op_array->scope;
274 } else {
275 if ((ce = zend_hash_find_ptr(EG(class_table),
276 Z_STR(op_array->literals[opline->op1.constant + 1]))) == NULL ||
277 (ce->type == ZEND_INTERNAL_CLASS &&
278 ce->info.internal.module->type != MODULE_PERSISTENT) ||
279 (ce->type == ZEND_USER_CLASS &&
280 ce->info.user.filename != op_array->filename)) {
281 break;
282 }
283 }
284 } else if (op_array->scope &&
285 opline->op1_type == IS_UNUSED &&
286 (opline->op1.num & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_SELF) {
287 /* for self::B */
288 ce = op_array->scope;
289 } else if (op_array->scope &&
290 opline->op1_type == IS_VAR &&
291 (opline - 1)->opcode == ZEND_FETCH_CLASS &&
292 ((opline - 1)->op1_type == IS_UNUSED &&
293 ((opline - 1)->extended_value & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_SELF) &&
294 (opline - 1)->result.var == opline->op1.var) {
295 /* for self::B */
296 ce = op_array->scope;
297 }
298
299 if (ce) {
300 zend_class_constant *cc;
301 zval *c, t;
302
303 if ((cc = zend_hash_find_ptr(&ce->constants_table,
304 Z_STR(ZEND_OP2_LITERAL(opline)))) != NULL &&
305 (Z_ACCESS_FLAGS(cc->value) & ZEND_ACC_PPP_MASK) == ZEND_ACC_PUBLIC) {
306 c = &cc->value;
307 if (Z_TYPE_P(c) == IS_CONSTANT_AST) {
308 break;
309 }
310 if (ZEND_IS_CONSTANT_TYPE(Z_TYPE_P(c))) {
311 if (!zend_optimizer_get_persistent_constant(Z_STR_P(c), &t, 1) ||
312 ZEND_IS_CONSTANT_TYPE(Z_TYPE(t))) {
313 break;
314 }
315 } else {
316 ZVAL_COPY_VALUE(&t, c);
317 zval_copy_ctor(&t);
318 }
319
320 if (opline->op1_type == IS_CONST) {
321 literal_dtor(&ZEND_OP1_LITERAL(opline));
322 } else if (opline->op1_type == IS_VAR) {
323 MAKE_NOP((opline - 1));
324 }
325 literal_dtor(&ZEND_OP2_LITERAL(opline));
326
327 if (zend_optimizer_replace_by_const(op_array, opline, IS_TMP_VAR, opline->result.var, &t)) {
328 MAKE_NOP(opline);
329 } else {
330 opline->opcode = ZEND_QM_ASSIGN;
331 opline->extended_value = 0;
332 SET_UNUSED(opline->op2);
333 zend_optimizer_update_op1_const(op_array, opline, &t);
334 }
335 }
336 }
337 }
338 break;
339
340 case ZEND_DO_ICALL: {
341 zend_op *send1_opline = opline - 1;
342 zend_op *send2_opline = NULL;
343 zend_op *init_opline = NULL;
344
345 while (send1_opline->opcode == ZEND_NOP) {
346 send1_opline--;
347 }
348 if (send1_opline->opcode != ZEND_SEND_VAL ||
349 send1_opline->op1_type != IS_CONST) {
350 /* don't colllect constants after unknown function call */
351 collect_constants = 0;
352 break;
353 }
354 if (send1_opline->op2.num == 2) {
355 send2_opline = send1_opline;
356 send1_opline--;
357 while (send1_opline->opcode == ZEND_NOP) {
358 send1_opline--;
359 }
360 if (send1_opline->opcode != ZEND_SEND_VAL ||
361 send1_opline->op1_type != IS_CONST) {
362 /* don't colllect constants after unknown function call */
363 collect_constants = 0;
364 break;
365 }
366 }
367 init_opline = send1_opline - 1;
368 while (init_opline->opcode == ZEND_NOP) {
369 init_opline--;
370 }
371 if (init_opline->opcode != ZEND_INIT_FCALL ||
372 init_opline->op2_type != IS_CONST ||
373 Z_TYPE(ZEND_OP2_LITERAL(init_opline)) != IS_STRING) {
374 /* don't colllect constants after unknown function call */
375 collect_constants = 0;
376 break;
377 }
378
379 /* define("name", scalar); */
380 if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("define")-1 &&
381 zend_binary_strcasecmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)), Z_STRLEN(ZEND_OP2_LITERAL(init_opline)), "define", sizeof("define")-1) == 0) {
382
383 if (Z_TYPE(ZEND_OP1_LITERAL(send1_opline)) == IS_STRING &&
384 send2_opline &&
385 Z_TYPE(ZEND_OP1_LITERAL(send2_opline)) <= IS_STRING) {
386
387 if (collect_constants) {
388 zend_optimizer_collect_constant(ctx, &ZEND_OP1_LITERAL(send1_opline), &ZEND_OP1_LITERAL(send2_opline));
389 }
390
391 if (RESULT_UNUSED(opline) &&
392 !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)))) {
393
394 opline->opcode = ZEND_DECLARE_CONST;
395 opline->op1_type = IS_CONST;
396 opline->op2_type = IS_CONST;
397 opline->result_type = IS_UNUSED;
398 opline->op1.constant = send1_opline->op1.constant;
399 opline->op2.constant = send2_opline->op1.constant;
400 opline->result.num = 0;
401
402 literal_dtor(&ZEND_OP2_LITERAL(init_opline));
403 MAKE_NOP(init_opline);
404 MAKE_NOP(send1_opline);
405 MAKE_NOP(send2_opline);
406 }
407 break;
408 }
409 }
410
411 /* pre-evaluate constant functions:
412 constant(x)
413 function_exists(x)
414 is_callable(x)
415 extension_loaded(x)
416 */
417 if (!send2_opline &&
418 Z_TYPE(ZEND_OP1_LITERAL(send1_opline)) == IS_STRING) {
419 if ((Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("function_exists")-1 &&
420 !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)),
421 "function_exists", sizeof("function_exists")-1) &&
422 !zend_optimizer_is_disabled_func("function_exists", sizeof("function_exists") - 1)) ||
423 (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("is_callable")-1 &&
424 !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)),
425 "is_callable", sizeof("is_callable")) &&
426 !zend_optimizer_is_disabled_func("is_callable", sizeof("is_callable") - 1))) {
427 zend_internal_function *func;
428 zend_string *lc_name = zend_string_tolower(
429 Z_STR(ZEND_OP1_LITERAL(send1_opline)));
430
431 if ((func = zend_hash_find_ptr(EG(function_table), lc_name)) != NULL
432 && func->type == ZEND_INTERNAL_FUNCTION
433 && func->module->type == MODULE_PERSISTENT
434 #ifdef ZEND_WIN32
435 && func->module->handle == NULL
436 #endif
437 ) {
438 zval t;
439 if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("is_callable") - 1 ||
440 func->handler != ZEND_FN(display_disabled_function)) {
441 ZVAL_TRUE(&t);
442 } else {
443 ZVAL_FALSE(&t);
444 }
445 literal_dtor(&ZEND_OP2_LITERAL(init_opline));
446 MAKE_NOP(init_opline);
447 literal_dtor(&ZEND_OP1_LITERAL(send1_opline));
448 MAKE_NOP(send1_opline);
449 if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_VAR, opline->result.var, &t)) {
450 MAKE_NOP(opline);
451 } else {
452 opline->opcode = ZEND_QM_ASSIGN;
453 opline->extended_value = 0;
454 SET_UNUSED(opline->op2);
455 zend_optimizer_update_op1_const(op_array, opline, &t);
456 }
457 }
458 zend_string_release(lc_name);
459 break;
460 } else if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("extension_loaded")-1 &&
461 !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)),
462 "extension_loaded", sizeof("extension_loaded")-1) &&
463 !zend_optimizer_is_disabled_func("extension_loaded", sizeof("extension_loaded") - 1)) {
464 zval t;
465 zend_string *lc_name = zend_string_tolower(
466 Z_STR(ZEND_OP1_LITERAL(send1_opline)));
467 zend_module_entry *m = zend_hash_find_ptr(&module_registry,
468 lc_name);
469
470 zend_string_release(lc_name);
471 if (!m) {
472 if (PG(enable_dl)) {
473 break;
474 } else {
475 ZVAL_FALSE(&t);
476 }
477 } else {
478 if (m->type == MODULE_PERSISTENT
479 #ifdef ZEND_WIN32
480 && m->handle == NULL
481 #endif
482 ) {
483 ZVAL_TRUE(&t);
484 } else {
485 break;
486 }
487 }
488
489 literal_dtor(&ZEND_OP2_LITERAL(init_opline));
490 MAKE_NOP(init_opline);
491 literal_dtor(&ZEND_OP1_LITERAL(send1_opline));
492 MAKE_NOP(send1_opline);
493 if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_VAR, opline->result.var, &t)) {
494 MAKE_NOP(opline);
495 } else {
496 opline->opcode = ZEND_QM_ASSIGN;
497 opline->extended_value = 0;
498 SET_UNUSED(opline->op2);
499 zend_optimizer_update_op1_const(op_array, opline, &t);
500 }
501 break;
502 } else if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("constant")-1 &&
503 !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)),
504 "constant", sizeof("constant")-1) &&
505 !zend_optimizer_is_disabled_func("constant", sizeof("constant") - 1)) {
506 zval t;
507
508 if (zend_optimizer_get_persistent_constant(Z_STR(ZEND_OP1_LITERAL(send1_opline)), &t, 1)) {
509 literal_dtor(&ZEND_OP2_LITERAL(init_opline));
510 MAKE_NOP(init_opline);
511 literal_dtor(&ZEND_OP1_LITERAL(send1_opline));
512 MAKE_NOP(send1_opline);
513 if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_VAR, opline->result.var, &t)) {
514 MAKE_NOP(opline);
515 } else {
516 opline->opcode = ZEND_QM_ASSIGN;
517 opline->extended_value = 0;
518 SET_UNUSED(opline->op2);
519 zend_optimizer_update_op1_const(op_array, opline, &t);
520 }
521 }
522 break;
523 /* dirname(IS_CONST/IS_STRING) -> IS_CONST/IS_STRING */
524 } else if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("dirname")-1 &&
525 !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)),
526 "dirname", sizeof("dirname") - 1) &&
527 !zend_optimizer_is_disabled_func("dirname", sizeof("dirname") - 1) &&
528 IS_ABSOLUTE_PATH(Z_STRVAL(ZEND_OP1_LITERAL(send1_opline)), Z_STRLEN(ZEND_OP1_LITERAL(send1_opline)))) {
529 zend_string *dirname = zend_string_init(Z_STRVAL(ZEND_OP1_LITERAL(send1_opline)), Z_STRLEN(ZEND_OP1_LITERAL(send1_opline)), 0);
530 ZSTR_LEN(dirname) = zend_dirname(ZSTR_VAL(dirname), ZSTR_LEN(dirname));
531 if (IS_ABSOLUTE_PATH(ZSTR_VAL(dirname), ZSTR_LEN(dirname))) {
532 zval t;
533
534 ZVAL_STR(&t, dirname);
535 literal_dtor(&ZEND_OP2_LITERAL(init_opline));
536 MAKE_NOP(init_opline);
537 literal_dtor(&ZEND_OP1_LITERAL(send1_opline));
538 MAKE_NOP(send1_opline);
539 if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_VAR, opline->result.var, &t)) {
540 MAKE_NOP(opline);
541 } else {
542 opline->opcode = ZEND_QM_ASSIGN;
543 opline->extended_value = 0;
544 SET_UNUSED(opline->op2);
545 zend_optimizer_update_op1_const(op_array, opline, &t);
546 }
547 } else {
548 zend_string_release(dirname);
549 }
550 break;
551 }
552 }
553 /* don't colllect constants after any other function call */
554 collect_constants = 0;
555 break;
556 }
557 case ZEND_STRLEN:
558 if (opline->op1_type == IS_CONST) {
559 zval t;
560
561 if (zend_optimizer_eval_strlen(&t, &ZEND_OP1_LITERAL(opline)) == SUCCESS) {
562 literal_dtor(&ZEND_OP1_LITERAL(opline));
563 if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_TMP_VAR, opline->result.var, &t)) {
564 MAKE_NOP(opline);
565 } else {
566 opline->opcode = ZEND_QM_ASSIGN;
567 zend_optimizer_update_op1_const(op_array, opline, &t);
568 }
569 }
570 }
571 break;
572 case ZEND_DEFINED:
573 {
574 zval c;
575 if (!zend_optimizer_get_persistent_constant(Z_STR(ZEND_OP1_LITERAL(opline)), &c, 0)) {
576 break;
577 }
578 ZVAL_TRUE(&c);
579 literal_dtor(&ZEND_OP1_LITERAL(opline));
580 if (zend_optimizer_replace_by_const(op_array, opline, IS_TMP_VAR, opline->result.var, &c)) {
581 MAKE_NOP(opline);
582 } else {
583 opline->opcode = ZEND_QM_ASSIGN;
584 zend_optimizer_update_op1_const(op_array, opline, &c);
585 }
586 }
587 break;
588 case ZEND_DECLARE_CONST:
589 if (collect_constants &&
590 Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING &&
591 Z_TYPE(ZEND_OP2_LITERAL(opline)) <= IS_STRING) {
592 zend_optimizer_collect_constant(ctx, &ZEND_OP1_LITERAL(opline), &ZEND_OP2_LITERAL(opline));
593 }
594 break;
595
596 case ZEND_RETURN:
597 case ZEND_RETURN_BY_REF:
598 case ZEND_GENERATOR_RETURN:
599 case ZEND_EXIT:
600 case ZEND_THROW:
601 case ZEND_CATCH:
602 case ZEND_FAST_CALL:
603 case ZEND_FAST_RET:
604 case ZEND_JMP:
605 case ZEND_JMPZNZ:
606 case ZEND_JMPZ:
607 case ZEND_JMPNZ:
608 case ZEND_JMPZ_EX:
609 case ZEND_JMPNZ_EX:
610 case ZEND_FE_RESET_R:
611 case ZEND_FE_RESET_RW:
612 case ZEND_FE_FETCH_R:
613 case ZEND_FE_FETCH_RW:
614 case ZEND_JMP_SET:
615 case ZEND_COALESCE:
616 case ZEND_ASSERT_CHECK:
617 collect_constants = 0;
618 break;
619 }
620 opline++;
621 i++;
622 }
623 }
624