xref: /PHP-8.3/Zend/zend_opcode.c (revision 5350952a)
1 /*
2    +----------------------------------------------------------------------+
3    | Zend Engine                                                          |
4    +----------------------------------------------------------------------+
5    | Copyright (c) Zend Technologies Ltd. (http://www.zend.com)           |
6    +----------------------------------------------------------------------+
7    | This source file is subject to version 2.00 of the Zend 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.zend.com/license/2_00.txt.                                |
11    | If you did not receive a copy of the Zend license and are unable to  |
12    | obtain it through the world-wide-web, please send a note to          |
13    | license@zend.com so we can mail you a copy immediately.              |
14    +----------------------------------------------------------------------+
15    | Authors: Andi Gutmans <andi@php.net>                                 |
16    |          Zeev Suraski <zeev@php.net>                                 |
17    |          Dmitry Stogov <dmitry@php.net>                              |
18    +----------------------------------------------------------------------+
19 */
20 
21 #include <stdio.h>
22 
23 #include "zend.h"
24 #include "zend_alloc.h"
25 #include "zend_compile.h"
26 #include "zend_extensions.h"
27 #include "zend_API.h"
28 #include "zend_sort.h"
29 #include "zend_constants.h"
30 #include "zend_observer.h"
31 
32 #include "zend_vm.h"
33 
zend_extension_op_array_ctor_handler(zend_extension * extension,zend_op_array * op_array)34 static void zend_extension_op_array_ctor_handler(zend_extension *extension, zend_op_array *op_array)
35 {
36 	if (extension->op_array_ctor) {
37 		extension->op_array_ctor(op_array);
38 	}
39 }
40 
zend_extension_op_array_dtor_handler(zend_extension * extension,zend_op_array * op_array)41 static void zend_extension_op_array_dtor_handler(zend_extension *extension, zend_op_array *op_array)
42 {
43 	if (extension->op_array_dtor) {
44 		extension->op_array_dtor(op_array);
45 	}
46 }
47 
init_op_array(zend_op_array * op_array,uint8_t type,int initial_ops_size)48 void init_op_array(zend_op_array *op_array, uint8_t type, int initial_ops_size)
49 {
50 	op_array->type = type;
51 	op_array->arg_flags[0] = 0;
52 	op_array->arg_flags[1] = 0;
53 	op_array->arg_flags[2] = 0;
54 
55 	op_array->refcount = (uint32_t *) emalloc(sizeof(uint32_t));
56 	*op_array->refcount = 1;
57 	op_array->last = 0;
58 	op_array->opcodes = emalloc(initial_ops_size * sizeof(zend_op));
59 
60 	op_array->last_var = 0;
61 	op_array->vars = NULL;
62 
63 	op_array->T = 0;
64 
65 	op_array->function_name = NULL;
66 	op_array->filename = zend_string_copy(zend_get_compiled_filename());
67 	op_array->doc_comment = NULL;
68 	op_array->attributes = NULL;
69 
70 	op_array->arg_info = NULL;
71 	op_array->num_args = 0;
72 	op_array->required_num_args = 0;
73 
74 	op_array->scope = NULL;
75 	op_array->prototype = NULL;
76 
77 	op_array->live_range = NULL;
78 	op_array->try_catch_array = NULL;
79 	op_array->last_live_range = 0;
80 
81 	op_array->static_variables = NULL;
82 	ZEND_MAP_PTR_INIT(op_array->static_variables_ptr, NULL);
83 	op_array->last_try_catch = 0;
84 
85 	op_array->fn_flags = 0;
86 
87 	op_array->last_literal = 0;
88 	op_array->literals = NULL;
89 
90 	op_array->num_dynamic_func_defs = 0;
91 	op_array->dynamic_func_defs = NULL;
92 
93 	ZEND_MAP_PTR_INIT(op_array->run_time_cache, NULL);
94 	op_array->cache_size = zend_op_array_extension_handles * sizeof(void*);
95 
96 	memset(op_array->reserved, 0, ZEND_MAX_RESERVED_RESOURCES * sizeof(void*));
97 
98 	if (zend_extension_flags & ZEND_EXTENSIONS_HAVE_OP_ARRAY_CTOR) {
99 		zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_op_array_ctor_handler, op_array);
100 	}
101 }
102 
destroy_zend_function(zend_function * function)103 ZEND_API void destroy_zend_function(zend_function *function)
104 {
105 	zval tmp;
106 
107 	ZVAL_PTR(&tmp, function);
108 	zend_function_dtor(&tmp);
109 }
110 
zend_type_release(zend_type type,bool persistent)111 ZEND_API void zend_type_release(zend_type type, bool persistent) {
112 	if (ZEND_TYPE_HAS_LIST(type)) {
113 		zend_type *list_type;
114 		ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(type), list_type) {
115 			zend_type_release(*list_type, persistent);
116 		} ZEND_TYPE_LIST_FOREACH_END();
117 		if (!ZEND_TYPE_USES_ARENA(type)) {
118 			pefree(ZEND_TYPE_LIST(type), persistent);
119 		}
120 	} else if (ZEND_TYPE_HAS_NAME(type)) {
121 		zend_string_release(ZEND_TYPE_NAME(type));
122 	}
123 }
124 
zend_free_internal_arg_info(zend_internal_function * function)125 void zend_free_internal_arg_info(zend_internal_function *function) {
126 	if ((function->fn_flags & (ZEND_ACC_HAS_RETURN_TYPE|ZEND_ACC_HAS_TYPE_HINTS)) &&
127 		function->arg_info) {
128 
129 		uint32_t i;
130 		uint32_t num_args = function->num_args + 1;
131 		zend_internal_arg_info *arg_info = function->arg_info - 1;
132 
133 		if (function->fn_flags & ZEND_ACC_VARIADIC) {
134 			num_args++;
135 		}
136 		for (i = 0 ; i < num_args; i++) {
137 			zend_type_release(arg_info[i].type, /* persistent */ 1);
138 		}
139 		free(arg_info);
140 	}
141 }
142 
zend_function_dtor(zval * zv)143 ZEND_API void zend_function_dtor(zval *zv)
144 {
145 	zend_function *function = Z_PTR_P(zv);
146 
147 	if (function->type == ZEND_USER_FUNCTION) {
148 		ZEND_ASSERT(function->common.function_name);
149 		destroy_op_array(&function->op_array);
150 		/* op_arrays are allocated on arena, so we don't have to free them */
151 	} else {
152 		ZEND_ASSERT(function->type == ZEND_INTERNAL_FUNCTION);
153 		ZEND_ASSERT(function->common.function_name);
154 		zend_string_release_ex(function->common.function_name, 1);
155 
156 		/* For methods this will be called explicitly. */
157 		if (!function->common.scope) {
158 			zend_free_internal_arg_info(&function->internal_function);
159 
160 			if (function->common.attributes) {
161 				zend_hash_release(function->common.attributes);
162 				function->common.attributes = NULL;
163 			}
164 		}
165 
166 		if (!(function->common.fn_flags & ZEND_ACC_ARENA_ALLOCATED)) {
167 			pefree(function, 1);
168 		}
169 	}
170 }
171 
zend_cleanup_internal_class_data(zend_class_entry * ce)172 ZEND_API void zend_cleanup_internal_class_data(zend_class_entry *ce)
173 {
174 	if (ZEND_MAP_PTR(ce->static_members_table) && CE_STATIC_MEMBERS(ce)) {
175 		zval *static_members = CE_STATIC_MEMBERS(ce);
176 		zval *p = static_members;
177 		zval *end = p + ce->default_static_members_count;
178 		ZEND_MAP_PTR_SET(ce->static_members_table, NULL);
179 		while (p != end) {
180 			if (UNEXPECTED(Z_ISREF_P(p))) {
181 				zend_property_info *prop_info;
182 				ZEND_REF_FOREACH_TYPE_SOURCES(Z_REF_P(p), prop_info) {
183 					if (prop_info->ce == ce && p - static_members == prop_info->offset) {
184 						ZEND_REF_DEL_TYPE_SOURCE(Z_REF_P(p), prop_info);
185 						break; /* stop iteration here, the array might be realloc()'ed */
186 					}
187 				} ZEND_REF_FOREACH_TYPE_SOURCES_END();
188 			}
189 			i_zval_ptr_dtor(p);
190 			p++;
191 		}
192 		efree(static_members);
193 	}
194 }
195 
_destroy_zend_class_traits_info(zend_class_entry * ce)196 static void _destroy_zend_class_traits_info(zend_class_entry *ce)
197 {
198 	uint32_t i;
199 
200 	for (i = 0; i < ce->num_traits; i++) {
201 		zend_string_release_ex(ce->trait_names[i].name, 0);
202 		zend_string_release_ex(ce->trait_names[i].lc_name, 0);
203 	}
204 	efree(ce->trait_names);
205 
206 	if (ce->trait_aliases) {
207 		i = 0;
208 		while (ce->trait_aliases[i]) {
209 			if (ce->trait_aliases[i]->trait_method.method_name) {
210 				zend_string_release_ex(ce->trait_aliases[i]->trait_method.method_name, 0);
211 			}
212 			if (ce->trait_aliases[i]->trait_method.class_name) {
213 				zend_string_release_ex(ce->trait_aliases[i]->trait_method.class_name, 0);
214 			}
215 
216 			if (ce->trait_aliases[i]->alias) {
217 				zend_string_release_ex(ce->trait_aliases[i]->alias, 0);
218 			}
219 
220 			efree(ce->trait_aliases[i]);
221 			i++;
222 		}
223 
224 		efree(ce->trait_aliases);
225 	}
226 
227 	if (ce->trait_precedences) {
228 		uint32_t j;
229 
230 		i = 0;
231 		while (ce->trait_precedences[i]) {
232 			zend_string_release_ex(ce->trait_precedences[i]->trait_method.method_name, 0);
233 			zend_string_release_ex(ce->trait_precedences[i]->trait_method.class_name, 0);
234 
235 			for (j = 0; j < ce->trait_precedences[i]->num_excludes; j++) {
236 				zend_string_release_ex(ce->trait_precedences[i]->exclude_class_names[j], 0);
237 			}
238 			efree(ce->trait_precedences[i]);
239 			i++;
240 		}
241 		efree(ce->trait_precedences);
242 	}
243 }
244 
zend_cleanup_mutable_class_data(zend_class_entry * ce)245 ZEND_API void zend_cleanup_mutable_class_data(zend_class_entry *ce)
246 {
247 	zend_class_mutable_data *mutable_data = ZEND_MAP_PTR_GET_IMM(ce->mutable_data);
248 
249 	if (mutable_data) {
250 		HashTable *constants_table;
251 		zval *p;
252 
253 		constants_table = mutable_data->constants_table;
254 		if (constants_table && constants_table != &ce->constants_table) {
255 			zend_class_constant *c;
256 
257 			ZEND_HASH_MAP_FOREACH_PTR(constants_table, c) {
258 				if (c->ce == ce || (Z_CONSTANT_FLAGS(c->value) & CONST_OWNED)) {
259 					zval_ptr_dtor_nogc(&c->value);
260 				}
261 			} ZEND_HASH_FOREACH_END();
262 			zend_hash_destroy(constants_table);
263 			mutable_data->constants_table = NULL;
264 		}
265 
266 		p = mutable_data->default_properties_table;
267 		if (p && p != ce->default_properties_table) {
268 			zval *end = p + ce->default_properties_count;
269 
270 			while (p < end) {
271 				zval_ptr_dtor_nogc(p);
272 				p++;
273 			}
274 			mutable_data->default_properties_table = NULL;
275 		}
276 
277 		if (mutable_data->backed_enum_table) {
278 			zend_hash_release(mutable_data->backed_enum_table);
279 			mutable_data->backed_enum_table = NULL;
280 		}
281 
282 		ZEND_MAP_PTR_SET_IMM(ce->mutable_data, NULL);
283 	}
284 }
285 
destroy_zend_class(zval * zv)286 ZEND_API void destroy_zend_class(zval *zv)
287 {
288 	zend_property_info *prop_info;
289 	zend_class_entry *ce = Z_PTR_P(zv);
290 	zend_function *fn;
291 
292 	if (ce->ce_flags & ZEND_ACC_IMMUTABLE) {
293 		return;
294 	}
295 
296 	/* We don't increase the refcount for class aliases,
297 	 * skip the destruction of aliases entirely. */
298 	if (UNEXPECTED(Z_TYPE_INFO_P(zv) == IS_ALIAS_PTR)) {
299 		return;
300 	}
301 
302 	if (ce->ce_flags & ZEND_ACC_FILE_CACHED) {
303 		zend_class_constant *c;
304 		zval *p, *end;
305 
306 		ZEND_HASH_MAP_FOREACH_PTR(&ce->constants_table, c) {
307 			if (c->ce == ce) {
308 				zval_ptr_dtor_nogc(&c->value);
309 			}
310 		} ZEND_HASH_FOREACH_END();
311 
312 		if (ce->default_properties_table) {
313 			p = ce->default_properties_table;
314 			end = p + ce->default_properties_count;
315 
316 			while (p < end) {
317 				zval_ptr_dtor_nogc(p);
318 				p++;
319 			}
320 		}
321 		return;
322 	}
323 
324 	ZEND_ASSERT(ce->refcount > 0);
325 
326 	if (--ce->refcount > 0) {
327 		return;
328 	}
329 
330 	switch (ce->type) {
331 		case ZEND_USER_CLASS:
332 			if (!(ce->ce_flags & ZEND_ACC_CACHED)) {
333 				if (ce->parent_name && !(ce->ce_flags & ZEND_ACC_RESOLVED_PARENT)) {
334 					zend_string_release_ex(ce->parent_name, 0);
335 				}
336 
337 				zend_string_release_ex(ce->name, 0);
338 				zend_string_release_ex(ce->info.user.filename, 0);
339 
340 				if (ce->info.user.doc_comment) {
341 					zend_string_release_ex(ce->info.user.doc_comment, 0);
342 				}
343 
344 				if (ce->attributes) {
345 					zend_hash_release(ce->attributes);
346 				}
347 
348 				if (ce->num_interfaces > 0 && !(ce->ce_flags & ZEND_ACC_RESOLVED_INTERFACES)) {
349 					uint32_t i;
350 
351 					for (i = 0; i < ce->num_interfaces; i++) {
352 						zend_string_release_ex(ce->interface_names[i].name, 0);
353 						zend_string_release_ex(ce->interface_names[i].lc_name, 0);
354 					}
355 					efree(ce->interface_names);
356 				}
357 
358 				if (ce->num_traits > 0) {
359 					_destroy_zend_class_traits_info(ce);
360 				}
361 			}
362 
363 			if (ce->default_properties_table) {
364 				zval *p = ce->default_properties_table;
365 				zval *end = p + ce->default_properties_count;
366 
367 				while (p != end) {
368 					i_zval_ptr_dtor(p);
369 					p++;
370 				}
371 				efree(ce->default_properties_table);
372 			}
373 			if (ce->default_static_members_table) {
374 				zval *p = ce->default_static_members_table;
375 				zval *end = p + ce->default_static_members_count;
376 
377 				while (p != end) {
378 					ZEND_ASSERT(!Z_ISREF_P(p));
379 					i_zval_ptr_dtor(p);
380 					p++;
381 				}
382 				efree(ce->default_static_members_table);
383 			}
384 			ZEND_HASH_MAP_FOREACH_PTR(&ce->properties_info, prop_info) {
385 				if (prop_info->ce == ce) {
386 					zend_string_release_ex(prop_info->name, 0);
387 					if (prop_info->doc_comment) {
388 						zend_string_release_ex(prop_info->doc_comment, 0);
389 					}
390 					if (prop_info->attributes) {
391 						zend_hash_release(prop_info->attributes);
392 					}
393 					zend_type_release(prop_info->type, /* persistent */ 0);
394 				}
395 			} ZEND_HASH_FOREACH_END();
396 			zend_hash_destroy(&ce->properties_info);
397 			zend_hash_destroy(&ce->function_table);
398 			if (zend_hash_num_elements(&ce->constants_table)) {
399 				zend_class_constant *c;
400 
401 				ZEND_HASH_MAP_FOREACH_PTR(&ce->constants_table, c) {
402 					if (c->ce == ce || (Z_CONSTANT_FLAGS(c->value) & CONST_OWNED)) {
403 						zval_ptr_dtor_nogc(&c->value);
404 						if (c->doc_comment) {
405 							zend_string_release_ex(c->doc_comment, 0);
406 						}
407 						if (c->attributes) {
408 							zend_hash_release(c->attributes);
409 						}
410 					}
411 				} ZEND_HASH_FOREACH_END();
412 			}
413 			zend_hash_destroy(&ce->constants_table);
414 			if (ce->num_interfaces > 0 && (ce->ce_flags & ZEND_ACC_RESOLVED_INTERFACES)) {
415 				efree(ce->interfaces);
416 			}
417 			if (ce->backed_enum_table) {
418 				zend_hash_release(ce->backed_enum_table);
419 			}
420 			break;
421 		case ZEND_INTERNAL_CLASS:
422 			if (ce->backed_enum_table) {
423 				zend_hash_release(ce->backed_enum_table);
424 			}
425 			if (ce->default_properties_table) {
426 				zval *p = ce->default_properties_table;
427 				zval *end = p + ce->default_properties_count;
428 
429 				while (p != end) {
430 					zval_internal_ptr_dtor(p);
431 					p++;
432 				}
433 				free(ce->default_properties_table);
434 			}
435 			if (ce->default_static_members_table) {
436 				zval *p = ce->default_static_members_table;
437 				zval *end = p + ce->default_static_members_count;
438 
439 				while (p != end) {
440 					zval_internal_ptr_dtor(p);
441 					p++;
442 				}
443 				free(ce->default_static_members_table);
444 			}
445 
446 			ZEND_HASH_MAP_FOREACH_PTR(&ce->properties_info, prop_info) {
447 				if (prop_info->ce == ce) {
448 					zend_string_release(prop_info->name);
449 					zend_type_release(prop_info->type, /* persistent */ 1);
450 					if (prop_info->attributes) {
451 						zend_hash_release(prop_info->attributes);
452 					}
453 					free(prop_info);
454 				}
455 			} ZEND_HASH_FOREACH_END();
456 			zend_hash_destroy(&ce->properties_info);
457 			zend_string_release_ex(ce->name, 1);
458 
459 			/* TODO: eliminate this loop for classes without functions with arg_info / attributes */
460 			ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, fn) {
461 				if (fn->common.scope == ce) {
462 					if (fn->common.fn_flags & (ZEND_ACC_HAS_RETURN_TYPE|ZEND_ACC_HAS_TYPE_HINTS)) {
463 						zend_free_internal_arg_info(&fn->internal_function);
464 					}
465 
466 					if (fn->common.attributes) {
467 						zend_hash_release(fn->common.attributes);
468 						fn->common.attributes = NULL;
469 					}
470 				}
471 			} ZEND_HASH_FOREACH_END();
472 
473 			zend_hash_destroy(&ce->function_table);
474 			if (zend_hash_num_elements(&ce->constants_table)) {
475 				zend_class_constant *c;
476 
477 				ZEND_HASH_MAP_FOREACH_PTR(&ce->constants_table, c) {
478 					if (c->ce == ce) {
479 						if (Z_TYPE(c->value) == IS_CONSTANT_AST) {
480 							/* We marked this as IMMUTABLE, but do need to free it when the
481 							 * class is destroyed. */
482 							ZEND_ASSERT(Z_ASTVAL(c->value)->kind == ZEND_AST_CONST_ENUM_INIT);
483 							free(Z_AST(c->value));
484 						} else {
485 							zval_internal_ptr_dtor(&c->value);
486 						}
487 						if (c->doc_comment) {
488 							zend_string_release_ex(c->doc_comment, 1);
489 						}
490 						if (c->attributes) {
491 							zend_hash_release(c->attributes);
492 						}
493 					}
494 					free(c);
495 				} ZEND_HASH_FOREACH_END();
496 				zend_hash_destroy(&ce->constants_table);
497 			}
498 			if (ce->iterator_funcs_ptr) {
499 				free(ce->iterator_funcs_ptr);
500 			}
501 			if (ce->arrayaccess_funcs_ptr) {
502 				free(ce->arrayaccess_funcs_ptr);
503 			}
504 			if (ce->num_interfaces > 0) {
505 				free(ce->interfaces);
506 			}
507 			if (ce->properties_info_table) {
508 				free(ce->properties_info_table);
509 			}
510 			if (ce->attributes) {
511 				zend_hash_release(ce->attributes);
512 			}
513 			free(ce);
514 			break;
515 	}
516 }
517 
zend_class_add_ref(zval * zv)518 void zend_class_add_ref(zval *zv)
519 {
520 	zend_class_entry *ce = Z_PTR_P(zv);
521 
522 	if (Z_TYPE_P(zv) != IS_ALIAS_PTR && !(ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
523 		ce->refcount++;
524 	}
525 }
526 
zend_destroy_static_vars(zend_op_array * op_array)527 ZEND_API void zend_destroy_static_vars(zend_op_array *op_array)
528 {
529 	if (ZEND_MAP_PTR(op_array->static_variables_ptr)) {
530 		HashTable *ht = ZEND_MAP_PTR_GET(op_array->static_variables_ptr);
531 		if (ht) {
532 			zend_array_destroy(ht);
533 			ZEND_MAP_PTR_SET(op_array->static_variables_ptr, NULL);
534 		}
535 	}
536 }
537 
destroy_op_array(zend_op_array * op_array)538 ZEND_API void destroy_op_array(zend_op_array *op_array)
539 {
540 	uint32_t i;
541 
542 	if ((op_array->fn_flags & ZEND_ACC_HEAP_RT_CACHE)
543 	 && ZEND_MAP_PTR(op_array->run_time_cache)) {
544 		efree(ZEND_MAP_PTR(op_array->run_time_cache));
545 	}
546 
547 	if (op_array->function_name) {
548 		zend_string_release_ex(op_array->function_name, 0);
549 	}
550 
551 	if (!op_array->refcount || --(*op_array->refcount) > 0) {
552 		return;
553 	}
554 
555 	efree_size(op_array->refcount, sizeof(*(op_array->refcount)));
556 
557 	if (op_array->vars) {
558 		i = op_array->last_var;
559 		while (i > 0) {
560 			i--;
561 			zend_string_release_ex(op_array->vars[i], 0);
562 		}
563 		efree(op_array->vars);
564 	}
565 
566 	if (op_array->literals) {
567 		zval *literal = op_array->literals;
568 		zval *end = literal + op_array->last_literal;
569 	 	while (literal < end) {
570 			zval_ptr_dtor_nogc(literal);
571 			literal++;
572 		}
573 		if (ZEND_USE_ABS_CONST_ADDR
574 		 || !(op_array->fn_flags & ZEND_ACC_DONE_PASS_TWO)) {
575 			efree(op_array->literals);
576 		}
577 	}
578 	efree(op_array->opcodes);
579 
580 	zend_string_release_ex(op_array->filename, 0);
581 	if (op_array->doc_comment) {
582 		zend_string_release_ex(op_array->doc_comment, 0);
583 	}
584 	if (op_array->attributes) {
585 		zend_hash_release(op_array->attributes);
586 	}
587 	if (op_array->live_range) {
588 		efree(op_array->live_range);
589 	}
590 	if (op_array->try_catch_array) {
591 		efree(op_array->try_catch_array);
592 	}
593 	if (zend_extension_flags & ZEND_EXTENSIONS_HAVE_OP_ARRAY_DTOR) {
594 		if (op_array->fn_flags & ZEND_ACC_DONE_PASS_TWO) {
595 			zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_op_array_dtor_handler, op_array);
596 		}
597 	}
598 	if (op_array->arg_info) {
599 		uint32_t num_args = op_array->num_args;
600 		zend_arg_info *arg_info = op_array->arg_info;
601 
602 		if (op_array->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
603 			arg_info--;
604 			num_args++;
605 		}
606 		if (op_array->fn_flags & ZEND_ACC_VARIADIC) {
607 			num_args++;
608 		}
609 		for (i = 0 ; i < num_args; i++) {
610 			if (arg_info[i].name) {
611 				zend_string_release_ex(arg_info[i].name, 0);
612 			}
613 			zend_type_release(arg_info[i].type, /* persistent */ 0);
614 		}
615 		efree(arg_info);
616 	}
617 	if (op_array->static_variables) {
618 		zend_array_destroy(op_array->static_variables);
619 	}
620 	if (op_array->num_dynamic_func_defs) {
621 		for (i = 0; i < op_array->num_dynamic_func_defs; i++) {
622 			/* Closures overwrite static_variables in their copy.
623 			 * Make sure to destroy them when the prototype function is destroyed. */
624 			if (op_array->dynamic_func_defs[i]->static_variables
625 					&& (op_array->dynamic_func_defs[i]->fn_flags & ZEND_ACC_CLOSURE)) {
626 				zend_array_destroy(op_array->dynamic_func_defs[i]->static_variables);
627 				op_array->dynamic_func_defs[i]->static_variables = NULL;
628 			}
629 			destroy_op_array(op_array->dynamic_func_defs[i]);
630 		}
631 		efree(op_array->dynamic_func_defs);
632 	}
633 }
634 
zend_update_extended_stmts(zend_op_array * op_array)635 static void zend_update_extended_stmts(zend_op_array *op_array)
636 {
637 	zend_op *opline = op_array->opcodes, *end=opline+op_array->last;
638 
639 	while (opline<end) {
640 		if (opline->opcode == ZEND_EXT_STMT) {
641 			if (opline+1<end) {
642 				if ((opline+1)->opcode == ZEND_EXT_STMT) {
643 					opline->opcode = ZEND_NOP;
644 					opline++;
645 					continue;
646 				}
647 				if (opline+1<end) {
648 					opline->lineno = (opline+1)->lineno;
649 				}
650 			} else {
651 				opline->opcode = ZEND_NOP;
652 			}
653 		}
654 		opline++;
655 	}
656 }
657 
zend_extension_op_array_handler(zend_extension * extension,zend_op_array * op_array)658 static void zend_extension_op_array_handler(zend_extension *extension, zend_op_array *op_array)
659 {
660 	if (extension->op_array_handler) {
661 		extension->op_array_handler(op_array);
662 	}
663 }
664 
zend_check_finally_breakout(zend_op_array * op_array,uint32_t op_num,uint32_t dst_num)665 static void zend_check_finally_breakout(zend_op_array *op_array, uint32_t op_num, uint32_t dst_num)
666 {
667 	int i;
668 
669 	for (i = 0; i < op_array->last_try_catch; i++) {
670 		if ((op_num < op_array->try_catch_array[i].finally_op ||
671 					op_num >= op_array->try_catch_array[i].finally_end)
672 				&& (dst_num >= op_array->try_catch_array[i].finally_op &&
673 					 dst_num <= op_array->try_catch_array[i].finally_end)) {
674 			CG(in_compilation) = 1;
675 			CG(active_op_array) = op_array;
676 			CG(zend_lineno) = op_array->opcodes[op_num].lineno;
677 			zend_error_noreturn(E_COMPILE_ERROR, "jump into a finally block is disallowed");
678 		} else if ((op_num >= op_array->try_catch_array[i].finally_op
679 					&& op_num <= op_array->try_catch_array[i].finally_end)
680 				&& (dst_num > op_array->try_catch_array[i].finally_end
681 					|| dst_num < op_array->try_catch_array[i].finally_op)) {
682 			CG(in_compilation) = 1;
683 			CG(active_op_array) = op_array;
684 			CG(zend_lineno) = op_array->opcodes[op_num].lineno;
685 			zend_error_noreturn(E_COMPILE_ERROR, "jump out of a finally block is disallowed");
686 		}
687 	}
688 }
689 
zend_get_brk_cont_target(const zend_op_array * op_array,const zend_op * opline)690 static uint32_t zend_get_brk_cont_target(const zend_op_array *op_array, const zend_op *opline) {
691 	int nest_levels = opline->op2.num;
692 	int array_offset = opline->op1.num;
693 	zend_brk_cont_element *jmp_to;
694 	do {
695 		jmp_to = &CG(context).brk_cont_array[array_offset];
696 		if (nest_levels > 1) {
697 			array_offset = jmp_to->parent;
698 		}
699 	} while (--nest_levels > 0);
700 
701 	return opline->opcode == ZEND_BRK ? jmp_to->brk : jmp_to->cont;
702 }
703 
emit_live_range_raw(zend_op_array * op_array,uint32_t var_num,uint32_t kind,uint32_t start,uint32_t end)704 static void emit_live_range_raw(
705 		zend_op_array *op_array, uint32_t var_num, uint32_t kind, uint32_t start, uint32_t end) {
706 	zend_live_range *range;
707 
708 	op_array->last_live_range++;
709 	op_array->live_range = erealloc(op_array->live_range,
710 		sizeof(zend_live_range) * op_array->last_live_range);
711 
712 	ZEND_ASSERT(start < end);
713 	range = &op_array->live_range[op_array->last_live_range - 1];
714 	range->var = EX_NUM_TO_VAR(op_array->last_var + var_num);
715 	range->var |= kind;
716 	range->start = start;
717 	range->end = end;
718 }
719 
emit_live_range(zend_op_array * op_array,uint32_t var_num,uint32_t start,uint32_t end,zend_needs_live_range_cb needs_live_range)720 static void emit_live_range(
721 		zend_op_array *op_array, uint32_t var_num, uint32_t start, uint32_t end,
722 		zend_needs_live_range_cb needs_live_range) {
723 	zend_op *def_opline = &op_array->opcodes[start], *orig_def_opline = def_opline;
724 	zend_op *use_opline = &op_array->opcodes[end];
725 	uint32_t kind;
726 
727 	switch (def_opline->opcode) {
728 		/* These should never be the first def. */
729 		case ZEND_ADD_ARRAY_ELEMENT:
730 		case ZEND_ADD_ARRAY_UNPACK:
731 		case ZEND_ROPE_ADD:
732 			ZEND_UNREACHABLE();
733 			return;
734 		/* Result is boolean, it doesn't have to be destroyed. */
735 		case ZEND_JMPZ_EX:
736 		case ZEND_JMPNZ_EX:
737 		case ZEND_BOOL:
738 		case ZEND_BOOL_NOT:
739 		/* Classes don't have to be destroyed. */
740 		case ZEND_FETCH_CLASS:
741 		case ZEND_DECLARE_ANON_CLASS:
742 		/* FAST_CALLs don't have to be destroyed. */
743 		case ZEND_FAST_CALL:
744 			return;
745 		case ZEND_BEGIN_SILENCE:
746 			kind = ZEND_LIVE_SILENCE;
747 			start++;
748 			break;
749 		case ZEND_ROPE_INIT:
750 			kind = ZEND_LIVE_ROPE;
751 			/* ROPE live ranges include the generating opcode. */
752 			def_opline--;
753 			break;
754 		case ZEND_FE_RESET_R:
755 		case ZEND_FE_RESET_RW:
756 			kind = ZEND_LIVE_LOOP;
757 			start++;
758 			break;
759 		/* Objects created via ZEND_NEW are only fully initialized
760 		 * after the DO_FCALL (constructor call).
761 		 * We are creating two live-ranges: ZEND_LINE_NEW for uninitialized
762 		 * part, and ZEND_LIVE_TMPVAR for initialized.
763 		 */
764 		case ZEND_NEW:
765 		{
766 			int level = 0;
767 			uint32_t orig_start = start;
768 
769 			while (def_opline + 1 < use_opline) {
770 				def_opline++;
771 				start++;
772 				switch (def_opline->opcode) {
773 					case ZEND_INIT_FCALL:
774 					case ZEND_INIT_FCALL_BY_NAME:
775 					case ZEND_INIT_NS_FCALL_BY_NAME:
776 					case ZEND_INIT_DYNAMIC_CALL:
777 					case ZEND_INIT_USER_CALL:
778 					case ZEND_INIT_METHOD_CALL:
779 					case ZEND_INIT_STATIC_METHOD_CALL:
780 					case ZEND_NEW:
781 						level++;
782 						break;
783 					case ZEND_DO_FCALL:
784 					case ZEND_DO_FCALL_BY_NAME:
785 					case ZEND_DO_ICALL:
786 					case ZEND_DO_UCALL:
787 						if (level == 0) {
788 							goto done;
789 						}
790 						level--;
791 						break;
792 				}
793 			}
794 done:
795 			emit_live_range_raw(op_array, var_num, ZEND_LIVE_NEW, orig_start + 1, start + 1);
796 			if (start + 1 == end) {
797 				/* Trivial live-range, no need to store it. */
798 				return;
799 			}
800 		}
801 		ZEND_FALLTHROUGH;
802 		default:
803 			start++;
804 			kind = ZEND_LIVE_TMPVAR;
805 
806 			/* Check hook to determine whether a live range is necessary,
807 			 * e.g. based on type info. */
808 			if (needs_live_range && !needs_live_range(op_array, orig_def_opline)) {
809 				return;
810 			}
811 			break;
812 		case ZEND_COPY_TMP:
813 		{
814 			/* COPY_TMP has a split live-range: One from the definition until the use in
815 			 * "null" branch, and another from the start of the "non-null" branch to the
816 			 * FREE opcode. */
817 			uint32_t rt_var_num = EX_NUM_TO_VAR(op_array->last_var + var_num);
818 			if (needs_live_range && !needs_live_range(op_array, orig_def_opline)) {
819 				return;
820 			}
821 
822 			kind = ZEND_LIVE_TMPVAR;
823 			if (use_opline->opcode != ZEND_FREE) {
824 				/* This can happen if one branch of the coalesce has been optimized away.
825 				 * In this case we should emit a normal live-range instead. */
826 				start++;
827 				break;
828 			}
829 
830 			zend_op *block_start_op = use_opline;
831 			while ((block_start_op-1)->opcode == ZEND_FREE) {
832 				block_start_op--;
833 			}
834 
835 			start = block_start_op - op_array->opcodes;
836 			if (start != end) {
837 				emit_live_range_raw(op_array, var_num, kind, start, end);
838 			}
839 
840 			do {
841 				use_opline--;
842 
843 				/* The use might have been optimized away, in which case we will hit the def
844 				 * instead. */
845 				if (use_opline->opcode == ZEND_COPY_TMP && use_opline->result.var == rt_var_num) {
846 					start = def_opline + 1 - op_array->opcodes;
847 					emit_live_range_raw(op_array, var_num, kind, start, end);
848 					return;
849 				}
850 			} while (!(
851 				((use_opline->op1_type & (IS_TMP_VAR|IS_VAR)) && use_opline->op1.var == rt_var_num) ||
852 				((use_opline->op2_type & (IS_TMP_VAR|IS_VAR)) && use_opline->op2.var == rt_var_num)
853 			));
854 
855 			start = def_opline + 1 - op_array->opcodes;
856 			end = use_opline - op_array->opcodes;
857 			emit_live_range_raw(op_array, var_num, kind, start, end);
858 			return;
859 		}
860 	}
861 
862 	emit_live_range_raw(op_array, var_num, kind, start, end);
863 }
864 
is_fake_def(zend_op * opline)865 static bool is_fake_def(zend_op *opline) {
866 	/* These opcodes only modify the result, not create it. */
867 	return opline->opcode == ZEND_ROPE_ADD
868 		|| opline->opcode == ZEND_ADD_ARRAY_ELEMENT
869 		|| opline->opcode == ZEND_ADD_ARRAY_UNPACK;
870 }
871 
keeps_op1_alive(zend_op * opline)872 static bool keeps_op1_alive(zend_op *opline) {
873 	/* These opcodes don't consume their OP1 operand,
874 	 * it is later freed by something else. */
875 	if (opline->opcode == ZEND_CASE
876 	 || opline->opcode == ZEND_CASE_STRICT
877 	 || opline->opcode == ZEND_SWITCH_LONG
878 	 || opline->opcode == ZEND_SWITCH_STRING
879 	 || opline->opcode == ZEND_MATCH
880 	 || opline->opcode == ZEND_FETCH_LIST_R
881 	 || opline->opcode == ZEND_FETCH_LIST_W
882 	 || opline->opcode == ZEND_COPY_TMP) {
883 		return 1;
884 	}
885 	ZEND_ASSERT(opline->opcode != ZEND_FE_FETCH_R
886 		&& opline->opcode != ZEND_FE_FETCH_RW
887 		&& opline->opcode != ZEND_VERIFY_RETURN_TYPE
888 		&& opline->opcode != ZEND_BIND_LEXICAL
889 		&& opline->opcode != ZEND_ROPE_ADD);
890 	return 0;
891 }
892 
893 /* Live ranges must be sorted by increasing start opline */
cmp_live_range(const zend_live_range * a,const zend_live_range * b)894 static int cmp_live_range(const zend_live_range *a, const zend_live_range *b) {
895 	return a->start - b->start;
896 }
swap_live_range(zend_live_range * a,zend_live_range * b)897 static void swap_live_range(zend_live_range *a, zend_live_range *b) {
898 	uint32_t tmp;
899 	tmp = a->var;
900 	a->var = b->var;
901 	b->var = tmp;
902 	tmp = a->start;
903 	a->start = b->start;
904 	b->start = tmp;
905 	tmp = a->end;
906 	a->end = b->end;
907 	b->end = tmp;
908 }
909 
zend_calc_live_ranges(zend_op_array * op_array,zend_needs_live_range_cb needs_live_range)910 static void zend_calc_live_ranges(
911 		zend_op_array *op_array, zend_needs_live_range_cb needs_live_range) {
912 	uint32_t opnum = op_array->last;
913 	zend_op *opline = &op_array->opcodes[opnum];
914 	ALLOCA_FLAG(use_heap)
915 	uint32_t var_offset = op_array->last_var;
916 	uint32_t *last_use = do_alloca(sizeof(uint32_t) * op_array->T, use_heap);
917 	memset(last_use, -1, sizeof(uint32_t) * op_array->T);
918 
919 	ZEND_ASSERT(!op_array->live_range);
920 	while (opnum > 0) {
921 		opnum--;
922 		opline--;
923 
924 		if ((opline->result_type & (IS_TMP_VAR|IS_VAR)) && !is_fake_def(opline)) {
925 			uint32_t var_num = EX_VAR_TO_NUM(opline->result.var) - var_offset;
926 			/* Defs without uses can occur for two reasons: Either because the result is
927 			 * genuinely unused (e.g. omitted FREE opcode for an unused boolean result), or
928 			 * because there are multiple defining opcodes (e.g. JMPZ_EX and QM_ASSIGN), in
929 			 * which case the last one starts the live range. As such, we can simply ignore
930 			 * missing uses here. */
931 			if (EXPECTED(last_use[var_num] != (uint32_t) -1)) {
932 				/* Skip trivial live-range */
933 				if (opnum + 1 != last_use[var_num]) {
934 					uint32_t num;
935 
936 #if 1
937 					/* OP_DATA uses only op1 operand */
938 					ZEND_ASSERT(opline->opcode != ZEND_OP_DATA);
939 					num = opnum;
940 #else
941 					/* OP_DATA is really part of the previous opcode. */
942 					num = opnum - (opline->opcode == ZEND_OP_DATA);
943 #endif
944 					emit_live_range(op_array, var_num, num, last_use[var_num], needs_live_range);
945 				}
946 				last_use[var_num] = (uint32_t) -1;
947 			}
948 		}
949 
950 		if ((opline->op1_type & (IS_TMP_VAR|IS_VAR))) {
951 			uint32_t var_num = EX_VAR_TO_NUM(opline->op1.var) - var_offset;
952 			if (EXPECTED(last_use[var_num] == (uint32_t) -1)) {
953 				if (EXPECTED(!keeps_op1_alive(opline))) {
954 					/* OP_DATA is really part of the previous opcode. */
955 					last_use[var_num] = opnum - (opline->opcode == ZEND_OP_DATA);
956 				}
957 			}
958 		}
959 		if (opline->op2_type & (IS_TMP_VAR|IS_VAR)) {
960 			uint32_t var_num = EX_VAR_TO_NUM(opline->op2.var) - var_offset;
961 			if (UNEXPECTED(opline->opcode == ZEND_FE_FETCH_R
962 					|| opline->opcode == ZEND_FE_FETCH_RW)) {
963 				/* OP2 of FE_FETCH is actually a def, not a use. */
964 				if (last_use[var_num] != (uint32_t) -1) {
965 					if (opnum + 1 != last_use[var_num]) {
966 						emit_live_range(
967 							op_array, var_num, opnum, last_use[var_num], needs_live_range);
968 					}
969 					last_use[var_num] = (uint32_t) -1;
970 				}
971 			} else if (EXPECTED(last_use[var_num] == (uint32_t) -1)) {
972 #if 1
973 				/* OP_DATA uses only op1 operand */
974 				ZEND_ASSERT(opline->opcode != ZEND_OP_DATA);
975 				last_use[var_num] = opnum;
976 #else
977 				/* OP_DATA is really part of the previous opcode. */
978 				last_use[var_num] = opnum - (opline->opcode == ZEND_OP_DATA);
979 #endif
980 			}
981 		}
982 	}
983 
984 	if (op_array->last_live_range > 1) {
985 		zend_live_range *r1 = op_array->live_range;
986 		zend_live_range *r2 = r1 + op_array->last_live_range - 1;
987 
988 		/* In most cases we need just revert the array */
989 		while (r1 < r2) {
990 			swap_live_range(r1, r2);
991 			r1++;
992 			r2--;
993 		}
994 
995 		r1 = op_array->live_range;
996 		r2 = r1 + op_array->last_live_range - 1;
997 		while (r1 < r2) {
998 			if (r1->start > (r1+1)->start) {
999 				zend_sort(r1, r2 - r1 + 1, sizeof(zend_live_range),
1000 					(compare_func_t) cmp_live_range, (swap_func_t) swap_live_range);
1001 				break;
1002 			}
1003 			r1++;
1004 		}
1005 	}
1006 
1007 	free_alloca(last_use, use_heap);
1008 }
1009 
zend_recalc_live_ranges(zend_op_array * op_array,zend_needs_live_range_cb needs_live_range)1010 ZEND_API void zend_recalc_live_ranges(
1011 		zend_op_array *op_array, zend_needs_live_range_cb needs_live_range) {
1012 	/* We assume that we never create live-ranges where there were none before. */
1013 	ZEND_ASSERT(op_array->live_range);
1014 	efree(op_array->live_range);
1015 	op_array->live_range = NULL;
1016 	op_array->last_live_range = 0;
1017 	zend_calc_live_ranges(op_array, needs_live_range);
1018 }
1019 
pass_two(zend_op_array * op_array)1020 ZEND_API void pass_two(zend_op_array *op_array)
1021 {
1022 	zend_op *opline, *end;
1023 
1024 	if (!ZEND_USER_CODE(op_array->type)) {
1025 		return;
1026 	}
1027 	if (CG(compiler_options) & ZEND_COMPILE_EXTENDED_STMT) {
1028 		zend_update_extended_stmts(op_array);
1029 	}
1030 	if (CG(compiler_options) & ZEND_COMPILE_HANDLE_OP_ARRAY) {
1031 		if (zend_extension_flags & ZEND_EXTENSIONS_HAVE_OP_ARRAY_HANDLER) {
1032 			zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_op_array_handler, op_array);
1033 		}
1034 	}
1035 
1036 	if (CG(context).vars_size != op_array->last_var) {
1037 		op_array->vars = (zend_string**) erealloc(op_array->vars, sizeof(zend_string*)*op_array->last_var);
1038 		CG(context).vars_size = op_array->last_var;
1039 	}
1040 
1041 #if ZEND_USE_ABS_CONST_ADDR
1042 	if (CG(context).opcodes_size != op_array->last) {
1043 		op_array->opcodes = (zend_op *) erealloc(op_array->opcodes, sizeof(zend_op)*op_array->last);
1044 		CG(context).opcodes_size = op_array->last;
1045 	}
1046 	if (CG(context).literals_size != op_array->last_literal) {
1047 		op_array->literals = (zval*)erealloc(op_array->literals, sizeof(zval) * op_array->last_literal);
1048 		CG(context).literals_size = op_array->last_literal;
1049 	}
1050 #else
1051 	op_array->opcodes = (zend_op *) erealloc(op_array->opcodes,
1052 		ZEND_MM_ALIGNED_SIZE_EX(sizeof(zend_op) * op_array->last, 16) +
1053 		sizeof(zval) * op_array->last_literal);
1054 	if (op_array->literals) {
1055 		memcpy(((char*)op_array->opcodes) + ZEND_MM_ALIGNED_SIZE_EX(sizeof(zend_op) * op_array->last, 16),
1056 			op_array->literals, sizeof(zval) * op_array->last_literal);
1057 		efree(op_array->literals);
1058 		op_array->literals = (zval*)(((char*)op_array->opcodes) + ZEND_MM_ALIGNED_SIZE_EX(sizeof(zend_op) * op_array->last, 16));
1059 	}
1060 	CG(context).opcodes_size = op_array->last;
1061 	CG(context).literals_size = op_array->last_literal;
1062 #endif
1063 
1064     op_array->T += ZEND_OBSERVER_ENABLED; // reserve last temporary for observers if enabled
1065 
1066 	/* Needs to be set directly after the opcode/literal reallocation, to ensure destruction
1067 	 * happens correctly if any of the following fixups generate a fatal error. */
1068 	op_array->fn_flags |= ZEND_ACC_DONE_PASS_TWO;
1069 
1070 	opline = op_array->opcodes;
1071 	end = opline + op_array->last;
1072 	while (opline < end) {
1073 		switch (opline->opcode) {
1074 			case ZEND_RECV_INIT:
1075 				{
1076 					zval *val = CT_CONSTANT(opline->op2);
1077 					if (Z_TYPE_P(val) == IS_CONSTANT_AST) {
1078 						uint32_t slot = ZEND_MM_ALIGNED_SIZE_EX(op_array->cache_size, 8);
1079 						Z_CACHE_SLOT_P(val) = slot;
1080 						op_array->cache_size += sizeof(zval);
1081 					}
1082 				}
1083 				break;
1084 			case ZEND_FAST_CALL:
1085 				opline->op1.opline_num = op_array->try_catch_array[opline->op1.num].finally_op;
1086 				ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, opline->op1);
1087 				break;
1088 			case ZEND_BRK:
1089 			case ZEND_CONT:
1090 				{
1091 					uint32_t jmp_target = zend_get_brk_cont_target(op_array, opline);
1092 
1093 					if (op_array->fn_flags & ZEND_ACC_HAS_FINALLY_BLOCK) {
1094 						zend_check_finally_breakout(op_array, opline - op_array->opcodes, jmp_target);
1095 					}
1096 					opline->opcode = ZEND_JMP;
1097 					opline->op1.opline_num = jmp_target;
1098 					opline->op2.num = 0;
1099 					ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, opline->op1);
1100 				}
1101 				break;
1102 			case ZEND_GOTO:
1103 				zend_resolve_goto_label(op_array, opline);
1104 				if (op_array->fn_flags & ZEND_ACC_HAS_FINALLY_BLOCK) {
1105 					zend_check_finally_breakout(op_array, opline - op_array->opcodes, opline->op1.opline_num);
1106 				}
1107 				ZEND_FALLTHROUGH;
1108 			case ZEND_JMP:
1109 				ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, opline->op1);
1110 				break;
1111 			case ZEND_JMPZ:
1112 			case ZEND_JMPNZ:
1113 			case ZEND_JMPZ_EX:
1114 			case ZEND_JMPNZ_EX:
1115 			case ZEND_JMP_SET:
1116 			case ZEND_COALESCE:
1117 			case ZEND_FE_RESET_R:
1118 			case ZEND_FE_RESET_RW:
1119 			case ZEND_JMP_NULL:
1120 			case ZEND_BIND_INIT_STATIC_OR_JMP:
1121 				ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, opline->op2);
1122 				break;
1123 			case ZEND_ASSERT_CHECK:
1124 			{
1125 				/* If result of assert is unused, result of check is unused as well */
1126 				zend_op *call = &op_array->opcodes[opline->op2.opline_num - 1];
1127 				if (call->opcode == ZEND_EXT_FCALL_END) {
1128 					call--;
1129 				}
1130 				if (call->result_type == IS_UNUSED) {
1131 					opline->result_type = IS_UNUSED;
1132 				}
1133 				ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, opline->op2);
1134 				break;
1135 			}
1136 			case ZEND_FE_FETCH_R:
1137 			case ZEND_FE_FETCH_RW:
1138 				/* absolute index to relative offset */
1139 				opline->extended_value = ZEND_OPLINE_NUM_TO_OFFSET(op_array, opline, opline->extended_value);
1140 				break;
1141 			case ZEND_CATCH:
1142 				if (!(opline->extended_value & ZEND_LAST_CATCH)) {
1143 					ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, opline->op2);
1144 				}
1145 				break;
1146 			case ZEND_RETURN:
1147 			case ZEND_RETURN_BY_REF:
1148 				if (op_array->fn_flags & ZEND_ACC_GENERATOR) {
1149 					opline->opcode = ZEND_GENERATOR_RETURN;
1150 				}
1151 				break;
1152 			case ZEND_SWITCH_LONG:
1153 			case ZEND_SWITCH_STRING:
1154 			case ZEND_MATCH:
1155 			{
1156 				/* absolute indexes to relative offsets */
1157 				HashTable *jumptable = Z_ARRVAL_P(CT_CONSTANT(opline->op2));
1158 				zval *zv;
1159 				ZEND_HASH_FOREACH_VAL(jumptable, zv) {
1160 					Z_LVAL_P(zv) = ZEND_OPLINE_NUM_TO_OFFSET(op_array, opline, Z_LVAL_P(zv));
1161 				} ZEND_HASH_FOREACH_END();
1162 
1163 				opline->extended_value = ZEND_OPLINE_NUM_TO_OFFSET(op_array, opline, opline->extended_value);
1164 				break;
1165 			}
1166 		}
1167 		if (opline->op1_type == IS_CONST) {
1168 			ZEND_PASS_TWO_UPDATE_CONSTANT(op_array, opline, opline->op1);
1169 		} else if (opline->op1_type & (IS_VAR|IS_TMP_VAR)) {
1170 			opline->op1.var = EX_NUM_TO_VAR(op_array->last_var + opline->op1.var);
1171 		}
1172 		if (opline->op2_type == IS_CONST) {
1173 			ZEND_PASS_TWO_UPDATE_CONSTANT(op_array, opline, opline->op2);
1174 		} else if (opline->op2_type & (IS_VAR|IS_TMP_VAR)) {
1175 			opline->op2.var = EX_NUM_TO_VAR(op_array->last_var + opline->op2.var);
1176 		}
1177 		if (opline->result_type & (IS_VAR|IS_TMP_VAR)) {
1178 			opline->result.var = EX_NUM_TO_VAR(op_array->last_var + opline->result.var);
1179 		}
1180 		ZEND_VM_SET_OPCODE_HANDLER(opline);
1181 		opline++;
1182 	}
1183 
1184 	zend_calc_live_ranges(op_array, NULL);
1185 
1186 	return;
1187 }
1188 
get_unary_op(int opcode)1189 ZEND_API unary_op_type get_unary_op(int opcode)
1190 {
1191 	switch (opcode) {
1192 		case ZEND_BW_NOT:
1193 			return (unary_op_type) bitwise_not_function;
1194 		case ZEND_BOOL_NOT:
1195 			return (unary_op_type) boolean_not_function;
1196 		default:
1197 			return (unary_op_type) NULL;
1198 	}
1199 }
1200 
get_binary_op(int opcode)1201 ZEND_API binary_op_type get_binary_op(int opcode)
1202 {
1203 	switch (opcode) {
1204 		case ZEND_ADD:
1205 			return (binary_op_type) add_function;
1206 		case ZEND_SUB:
1207 			return (binary_op_type) sub_function;
1208 		case ZEND_MUL:
1209 			return (binary_op_type) mul_function;
1210 		case ZEND_POW:
1211 			return (binary_op_type) pow_function;
1212 		case ZEND_DIV:
1213 			return (binary_op_type) div_function;
1214 		case ZEND_MOD:
1215 			return (binary_op_type) mod_function;
1216 		case ZEND_SL:
1217 			return (binary_op_type) shift_left_function;
1218 		case ZEND_SR:
1219 			return (binary_op_type) shift_right_function;
1220 		case ZEND_FAST_CONCAT:
1221 		case ZEND_CONCAT:
1222 			return (binary_op_type) concat_function;
1223 		case ZEND_IS_IDENTICAL:
1224 		case ZEND_CASE_STRICT:
1225 			return (binary_op_type) is_identical_function;
1226 		case ZEND_IS_NOT_IDENTICAL:
1227 			return (binary_op_type) is_not_identical_function;
1228 		case ZEND_IS_EQUAL:
1229 		case ZEND_CASE:
1230 			return (binary_op_type) is_equal_function;
1231 		case ZEND_IS_NOT_EQUAL:
1232 			return (binary_op_type) is_not_equal_function;
1233 		case ZEND_IS_SMALLER:
1234 			return (binary_op_type) is_smaller_function;
1235 		case ZEND_IS_SMALLER_OR_EQUAL:
1236 			return (binary_op_type) is_smaller_or_equal_function;
1237 		case ZEND_SPACESHIP:
1238 			return (binary_op_type) compare_function;
1239 		case ZEND_BW_OR:
1240 			return (binary_op_type) bitwise_or_function;
1241 		case ZEND_BW_AND:
1242 			return (binary_op_type) bitwise_and_function;
1243 		case ZEND_BW_XOR:
1244 			return (binary_op_type) bitwise_xor_function;
1245 		case ZEND_BOOL_XOR:
1246 			return (binary_op_type) boolean_xor_function;
1247 		default:
1248 			ZEND_UNREACHABLE();
1249 			return (binary_op_type) NULL;
1250 	}
1251 }
1252