xref: /PHP-8.2/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,zend_uchar type,int initial_ops_size)48 void init_op_array(zend_op_array *op_array, zend_uchar 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 	if (ce->ce_flags & ZEND_ACC_FILE_CACHED) {
297 		zend_class_constant *c;
298 		zval *p, *end;
299 
300 		ZEND_HASH_MAP_FOREACH_PTR(&ce->constants_table, c) {
301 			if (c->ce == ce) {
302 				zval_ptr_dtor_nogc(&c->value);
303 			}
304 		} ZEND_HASH_FOREACH_END();
305 
306 		if (ce->default_properties_table) {
307 			p = ce->default_properties_table;
308 			end = p + ce->default_properties_count;
309 
310 			while (p < end) {
311 				zval_ptr_dtor_nogc(p);
312 				p++;
313 			}
314 		}
315 		return;
316 	}
317 
318 	if (--ce->refcount > 0) {
319 		return;
320 	}
321 
322 	switch (ce->type) {
323 		case ZEND_USER_CLASS:
324 			if (!(ce->ce_flags & ZEND_ACC_CACHED)) {
325 				if (ce->parent_name && !(ce->ce_flags & ZEND_ACC_RESOLVED_PARENT)) {
326 					zend_string_release_ex(ce->parent_name, 0);
327 				}
328 
329 				zend_string_release_ex(ce->name, 0);
330 				zend_string_release_ex(ce->info.user.filename, 0);
331 
332 				if (ce->info.user.doc_comment) {
333 					zend_string_release_ex(ce->info.user.doc_comment, 0);
334 				}
335 
336 				if (ce->attributes) {
337 					zend_hash_release(ce->attributes);
338 				}
339 
340 				if (ce->num_interfaces > 0 && !(ce->ce_flags & ZEND_ACC_RESOLVED_INTERFACES)) {
341 					uint32_t i;
342 
343 					for (i = 0; i < ce->num_interfaces; i++) {
344 						zend_string_release_ex(ce->interface_names[i].name, 0);
345 						zend_string_release_ex(ce->interface_names[i].lc_name, 0);
346 					}
347 					efree(ce->interface_names);
348 				}
349 
350 				if (ce->num_traits > 0) {
351 					_destroy_zend_class_traits_info(ce);
352 				}
353 			}
354 
355 			if (ce->default_properties_table) {
356 				zval *p = ce->default_properties_table;
357 				zval *end = p + ce->default_properties_count;
358 
359 				while (p != end) {
360 					i_zval_ptr_dtor(p);
361 					p++;
362 				}
363 				efree(ce->default_properties_table);
364 			}
365 			if (ce->default_static_members_table) {
366 				zval *p = ce->default_static_members_table;
367 				zval *end = p + ce->default_static_members_count;
368 
369 				while (p != end) {
370 					ZEND_ASSERT(!Z_ISREF_P(p));
371 					i_zval_ptr_dtor(p);
372 					p++;
373 				}
374 				efree(ce->default_static_members_table);
375 			}
376 			ZEND_HASH_MAP_FOREACH_PTR(&ce->properties_info, prop_info) {
377 				if (prop_info->ce == ce) {
378 					zend_string_release_ex(prop_info->name, 0);
379 					if (prop_info->doc_comment) {
380 						zend_string_release_ex(prop_info->doc_comment, 0);
381 					}
382 					if (prop_info->attributes) {
383 						zend_hash_release(prop_info->attributes);
384 					}
385 					zend_type_release(prop_info->type, /* persistent */ 0);
386 				}
387 			} ZEND_HASH_FOREACH_END();
388 			zend_hash_destroy(&ce->properties_info);
389 			zend_hash_destroy(&ce->function_table);
390 			if (zend_hash_num_elements(&ce->constants_table)) {
391 				zend_class_constant *c;
392 
393 				ZEND_HASH_MAP_FOREACH_PTR(&ce->constants_table, c) {
394 					if (c->ce == ce || (Z_CONSTANT_FLAGS(c->value) & CONST_OWNED)) {
395 						zval_ptr_dtor_nogc(&c->value);
396 						if (c->doc_comment) {
397 							zend_string_release_ex(c->doc_comment, 0);
398 						}
399 						if (c->attributes) {
400 							zend_hash_release(c->attributes);
401 						}
402 					}
403 				} ZEND_HASH_FOREACH_END();
404 			}
405 			zend_hash_destroy(&ce->constants_table);
406 			if (ce->num_interfaces > 0 && (ce->ce_flags & ZEND_ACC_RESOLVED_INTERFACES)) {
407 				efree(ce->interfaces);
408 			}
409 			if (ce->backed_enum_table) {
410 				zend_hash_release(ce->backed_enum_table);
411 			}
412 			break;
413 		case ZEND_INTERNAL_CLASS:
414 			if (ce->backed_enum_table) {
415 				zend_hash_release(ce->backed_enum_table);
416 			}
417 			if (ce->default_properties_table) {
418 				zval *p = ce->default_properties_table;
419 				zval *end = p + ce->default_properties_count;
420 
421 				while (p != end) {
422 					zval_internal_ptr_dtor(p);
423 					p++;
424 				}
425 				free(ce->default_properties_table);
426 			}
427 			if (ce->default_static_members_table) {
428 				zval *p = ce->default_static_members_table;
429 				zval *end = p + ce->default_static_members_count;
430 
431 				while (p != end) {
432 					zval_internal_ptr_dtor(p);
433 					p++;
434 				}
435 				free(ce->default_static_members_table);
436 			}
437 
438 			ZEND_HASH_MAP_FOREACH_PTR(&ce->properties_info, prop_info) {
439 				if (prop_info->ce == ce) {
440 					zend_string_release(prop_info->name);
441 					zend_type_release(prop_info->type, /* persistent */ 1);
442 					free(prop_info);
443 				}
444 			} ZEND_HASH_FOREACH_END();
445 			zend_hash_destroy(&ce->properties_info);
446 			zend_string_release_ex(ce->name, 1);
447 
448 			/* TODO: eliminate this loop for classes without functions with arg_info / attributes */
449 			ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, fn) {
450 				if (fn->common.scope == ce) {
451 					if (fn->common.fn_flags & (ZEND_ACC_HAS_RETURN_TYPE|ZEND_ACC_HAS_TYPE_HINTS)) {
452 						zend_free_internal_arg_info(&fn->internal_function);
453 					}
454 
455 					if (fn->common.attributes) {
456 						zend_hash_release(fn->common.attributes);
457 						fn->common.attributes = NULL;
458 					}
459 				}
460 			} ZEND_HASH_FOREACH_END();
461 
462 			zend_hash_destroy(&ce->function_table);
463 			if (zend_hash_num_elements(&ce->constants_table)) {
464 				zend_class_constant *c;
465 
466 				ZEND_HASH_MAP_FOREACH_PTR(&ce->constants_table, c) {
467 					if (c->ce == ce) {
468 						if (Z_TYPE(c->value) == IS_CONSTANT_AST) {
469 							/* We marked this as IMMUTABLE, but do need to free it when the
470 							 * class is destroyed. */
471 							ZEND_ASSERT(Z_ASTVAL(c->value)->kind == ZEND_AST_CONST_ENUM_INIT);
472 							free(Z_AST(c->value));
473 						} else {
474 							zval_internal_ptr_dtor(&c->value);
475 						}
476 						if (c->doc_comment) {
477 							zend_string_release_ex(c->doc_comment, 1);
478 						}
479 						if (c->attributes) {
480 							zend_hash_release(c->attributes);
481 						}
482 					}
483 					free(c);
484 				} ZEND_HASH_FOREACH_END();
485 				zend_hash_destroy(&ce->constants_table);
486 			}
487 			if (ce->iterator_funcs_ptr) {
488 				free(ce->iterator_funcs_ptr);
489 			}
490 			if (ce->arrayaccess_funcs_ptr) {
491 				free(ce->arrayaccess_funcs_ptr);
492 			}
493 			if (ce->num_interfaces > 0) {
494 				free(ce->interfaces);
495 			}
496 			if (ce->properties_info_table) {
497 				free(ce->properties_info_table);
498 			}
499 			if (ce->attributes) {
500 				zend_hash_release(ce->attributes);
501 			}
502 			free(ce);
503 			break;
504 	}
505 }
506 
zend_class_add_ref(zval * zv)507 void zend_class_add_ref(zval *zv)
508 {
509 	zend_class_entry *ce = Z_PTR_P(zv);
510 
511 	if (!(ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
512 		ce->refcount++;
513 	}
514 }
515 
zend_destroy_static_vars(zend_op_array * op_array)516 ZEND_API void zend_destroy_static_vars(zend_op_array *op_array)
517 {
518 	if (ZEND_MAP_PTR(op_array->static_variables_ptr)) {
519 		HashTable *ht = ZEND_MAP_PTR_GET(op_array->static_variables_ptr);
520 		if (ht) {
521 			zend_array_destroy(ht);
522 			ZEND_MAP_PTR_SET(op_array->static_variables_ptr, NULL);
523 		}
524 	}
525 }
526 
destroy_op_array(zend_op_array * op_array)527 ZEND_API void destroy_op_array(zend_op_array *op_array)
528 {
529 	uint32_t i;
530 
531 	if ((op_array->fn_flags & ZEND_ACC_HEAP_RT_CACHE)
532 	 && ZEND_MAP_PTR(op_array->run_time_cache)) {
533 		efree(ZEND_MAP_PTR(op_array->run_time_cache));
534 	}
535 
536 	if (op_array->function_name) {
537 		zend_string_release_ex(op_array->function_name, 0);
538 	}
539 
540 	if (!op_array->refcount || --(*op_array->refcount) > 0) {
541 		return;
542 	}
543 
544 	efree_size(op_array->refcount, sizeof(*(op_array->refcount)));
545 
546 	if (op_array->vars) {
547 		i = op_array->last_var;
548 		while (i > 0) {
549 			i--;
550 			zend_string_release_ex(op_array->vars[i], 0);
551 		}
552 		efree(op_array->vars);
553 	}
554 
555 	if (op_array->literals) {
556 		zval *literal = op_array->literals;
557 		zval *end = literal + op_array->last_literal;
558 	 	while (literal < end) {
559 			zval_ptr_dtor_nogc(literal);
560 			literal++;
561 		}
562 		if (ZEND_USE_ABS_CONST_ADDR
563 		 || !(op_array->fn_flags & ZEND_ACC_DONE_PASS_TWO)) {
564 			efree(op_array->literals);
565 		}
566 	}
567 	efree(op_array->opcodes);
568 
569 	zend_string_release_ex(op_array->filename, 0);
570 	if (op_array->doc_comment) {
571 		zend_string_release_ex(op_array->doc_comment, 0);
572 	}
573 	if (op_array->attributes) {
574 		zend_hash_release(op_array->attributes);
575 	}
576 	if (op_array->live_range) {
577 		efree(op_array->live_range);
578 	}
579 	if (op_array->try_catch_array) {
580 		efree(op_array->try_catch_array);
581 	}
582 	if (zend_extension_flags & ZEND_EXTENSIONS_HAVE_OP_ARRAY_DTOR) {
583 		if (op_array->fn_flags & ZEND_ACC_DONE_PASS_TWO) {
584 			zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_op_array_dtor_handler, op_array);
585 		}
586 	}
587 	if (op_array->arg_info) {
588 		uint32_t num_args = op_array->num_args;
589 		zend_arg_info *arg_info = op_array->arg_info;
590 
591 		if (op_array->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
592 			arg_info--;
593 			num_args++;
594 		}
595 		if (op_array->fn_flags & ZEND_ACC_VARIADIC) {
596 			num_args++;
597 		}
598 		for (i = 0 ; i < num_args; i++) {
599 			if (arg_info[i].name) {
600 				zend_string_release_ex(arg_info[i].name, 0);
601 			}
602 			zend_type_release(arg_info[i].type, /* persistent */ 0);
603 		}
604 		efree(arg_info);
605 	}
606 	if (op_array->static_variables) {
607 		zend_array_destroy(op_array->static_variables);
608 	}
609 	if (op_array->num_dynamic_func_defs) {
610 		for (i = 0; i < op_array->num_dynamic_func_defs; i++) {
611 			/* Closures overwrite static_variables in their copy.
612 			 * Make sure to destroy them when the prototype function is destroyed. */
613 			if (op_array->dynamic_func_defs[i]->static_variables
614 					&& (op_array->dynamic_func_defs[i]->fn_flags & ZEND_ACC_CLOSURE)) {
615 				zend_array_destroy(op_array->dynamic_func_defs[i]->static_variables);
616 				op_array->dynamic_func_defs[i]->static_variables = NULL;
617 			}
618 			destroy_op_array(op_array->dynamic_func_defs[i]);
619 		}
620 		efree(op_array->dynamic_func_defs);
621 	}
622 }
623 
zend_update_extended_stmts(zend_op_array * op_array)624 static void zend_update_extended_stmts(zend_op_array *op_array)
625 {
626 	zend_op *opline = op_array->opcodes, *end=opline+op_array->last;
627 
628 	while (opline<end) {
629 		if (opline->opcode == ZEND_EXT_STMT) {
630 			if (opline+1<end) {
631 				if ((opline+1)->opcode == ZEND_EXT_STMT) {
632 					opline->opcode = ZEND_NOP;
633 					opline++;
634 					continue;
635 				}
636 				if (opline+1<end) {
637 					opline->lineno = (opline+1)->lineno;
638 				}
639 			} else {
640 				opline->opcode = ZEND_NOP;
641 			}
642 		}
643 		opline++;
644 	}
645 }
646 
zend_extension_op_array_handler(zend_extension * extension,zend_op_array * op_array)647 static void zend_extension_op_array_handler(zend_extension *extension, zend_op_array *op_array)
648 {
649 	if (extension->op_array_handler) {
650 		extension->op_array_handler(op_array);
651 	}
652 }
653 
zend_check_finally_breakout(zend_op_array * op_array,uint32_t op_num,uint32_t dst_num)654 static void zend_check_finally_breakout(zend_op_array *op_array, uint32_t op_num, uint32_t dst_num)
655 {
656 	int i;
657 
658 	for (i = 0; i < op_array->last_try_catch; i++) {
659 		if ((op_num < op_array->try_catch_array[i].finally_op ||
660 					op_num >= op_array->try_catch_array[i].finally_end)
661 				&& (dst_num >= op_array->try_catch_array[i].finally_op &&
662 					 dst_num <= op_array->try_catch_array[i].finally_end)) {
663 			CG(in_compilation) = 1;
664 			CG(active_op_array) = op_array;
665 			CG(zend_lineno) = op_array->opcodes[op_num].lineno;
666 			zend_error_noreturn(E_COMPILE_ERROR, "jump into a finally block is disallowed");
667 		} else if ((op_num >= op_array->try_catch_array[i].finally_op
668 					&& op_num <= op_array->try_catch_array[i].finally_end)
669 				&& (dst_num > op_array->try_catch_array[i].finally_end
670 					|| dst_num < op_array->try_catch_array[i].finally_op)) {
671 			CG(in_compilation) = 1;
672 			CG(active_op_array) = op_array;
673 			CG(zend_lineno) = op_array->opcodes[op_num].lineno;
674 			zend_error_noreturn(E_COMPILE_ERROR, "jump out of a finally block is disallowed");
675 		}
676 	}
677 }
678 
zend_get_brk_cont_target(const zend_op_array * op_array,const zend_op * opline)679 static uint32_t zend_get_brk_cont_target(const zend_op_array *op_array, const zend_op *opline) {
680 	int nest_levels = opline->op2.num;
681 	int array_offset = opline->op1.num;
682 	zend_brk_cont_element *jmp_to;
683 	do {
684 		jmp_to = &CG(context).brk_cont_array[array_offset];
685 		if (nest_levels > 1) {
686 			array_offset = jmp_to->parent;
687 		}
688 	} while (--nest_levels > 0);
689 
690 	return opline->opcode == ZEND_BRK ? jmp_to->brk : jmp_to->cont;
691 }
692 
emit_live_range_raw(zend_op_array * op_array,uint32_t var_num,uint32_t kind,uint32_t start,uint32_t end)693 static void emit_live_range_raw(
694 		zend_op_array *op_array, uint32_t var_num, uint32_t kind, uint32_t start, uint32_t end) {
695 	zend_live_range *range;
696 
697 	op_array->last_live_range++;
698 	op_array->live_range = erealloc(op_array->live_range,
699 		sizeof(zend_live_range) * op_array->last_live_range);
700 
701 	ZEND_ASSERT(start < end);
702 	range = &op_array->live_range[op_array->last_live_range - 1];
703 	range->var = EX_NUM_TO_VAR(op_array->last_var + var_num);
704 	range->var |= kind;
705 	range->start = start;
706 	range->end = end;
707 }
708 
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)709 static void emit_live_range(
710 		zend_op_array *op_array, uint32_t var_num, uint32_t start, uint32_t end,
711 		zend_needs_live_range_cb needs_live_range) {
712 	zend_op *def_opline = &op_array->opcodes[start], *orig_def_opline = def_opline;
713 	zend_op *use_opline = &op_array->opcodes[end];
714 	uint32_t kind;
715 
716 	switch (def_opline->opcode) {
717 		/* These should never be the first def. */
718 		case ZEND_ADD_ARRAY_ELEMENT:
719 		case ZEND_ADD_ARRAY_UNPACK:
720 		case ZEND_ROPE_ADD:
721 			ZEND_UNREACHABLE();
722 			return;
723 		/* Result is boolean, it doesn't have to be destroyed. */
724 		case ZEND_JMPZ_EX:
725 		case ZEND_JMPNZ_EX:
726 		case ZEND_BOOL:
727 		case ZEND_BOOL_NOT:
728 		/* Classes don't have to be destroyed. */
729 		case ZEND_FETCH_CLASS:
730 		case ZEND_DECLARE_ANON_CLASS:
731 		/* FAST_CALLs don't have to be destroyed. */
732 		case ZEND_FAST_CALL:
733 			return;
734 		case ZEND_BEGIN_SILENCE:
735 			kind = ZEND_LIVE_SILENCE;
736 			start++;
737 			break;
738 		case ZEND_ROPE_INIT:
739 			kind = ZEND_LIVE_ROPE;
740 			/* ROPE live ranges include the generating opcode. */
741 			def_opline--;
742 			break;
743 		case ZEND_FE_RESET_R:
744 		case ZEND_FE_RESET_RW:
745 			kind = ZEND_LIVE_LOOP;
746 			start++;
747 			break;
748 		/* Objects created via ZEND_NEW are only fully initialized
749 		 * after the DO_FCALL (constructor call).
750 		 * We are creating two live-ranges: ZEND_LINE_NEW for uninitialized
751 		 * part, and ZEND_LIVE_TMPVAR for initialized.
752 		 */
753 		case ZEND_NEW:
754 		{
755 			int level = 0;
756 			uint32_t orig_start = start;
757 
758 			while (def_opline + 1 < use_opline) {
759 				def_opline++;
760 				start++;
761 				switch (def_opline->opcode) {
762 					case ZEND_INIT_FCALL:
763 					case ZEND_INIT_FCALL_BY_NAME:
764 					case ZEND_INIT_NS_FCALL_BY_NAME:
765 					case ZEND_INIT_DYNAMIC_CALL:
766 					case ZEND_INIT_USER_CALL:
767 					case ZEND_INIT_METHOD_CALL:
768 					case ZEND_INIT_STATIC_METHOD_CALL:
769 					case ZEND_NEW:
770 						level++;
771 						break;
772 					case ZEND_DO_FCALL:
773 					case ZEND_DO_FCALL_BY_NAME:
774 					case ZEND_DO_ICALL:
775 					case ZEND_DO_UCALL:
776 						if (level == 0) {
777 							goto done;
778 						}
779 						level--;
780 						break;
781 				}
782 			}
783 done:
784 			emit_live_range_raw(op_array, var_num, ZEND_LIVE_NEW, orig_start + 1, start + 1);
785 			if (start + 1 == end) {
786 				/* Trivial live-range, no need to store it. */
787 				return;
788 			}
789 		}
790 		ZEND_FALLTHROUGH;
791 		default:
792 			start++;
793 			kind = ZEND_LIVE_TMPVAR;
794 
795 			/* Check hook to determine whether a live range is necessary,
796 			 * e.g. based on type info. */
797 			if (needs_live_range && !needs_live_range(op_array, orig_def_opline)) {
798 				return;
799 			}
800 			break;
801 		case ZEND_COPY_TMP:
802 		{
803 			/* COPY_TMP has a split live-range: One from the definition until the use in
804 			 * "null" branch, and another from the start of the "non-null" branch to the
805 			 * FREE opcode. */
806 			uint32_t rt_var_num = EX_NUM_TO_VAR(op_array->last_var + var_num);
807 			if (needs_live_range && !needs_live_range(op_array, orig_def_opline)) {
808 				return;
809 			}
810 
811 			kind = ZEND_LIVE_TMPVAR;
812 			if (use_opline->opcode != ZEND_FREE) {
813 				/* This can happen if one branch of the coalesce has been optimized away.
814 				 * In this case we should emit a normal live-range instead. */
815 				start++;
816 				break;
817 			}
818 
819 			zend_op *block_start_op = use_opline;
820 			while ((block_start_op-1)->opcode == ZEND_FREE) {
821 				block_start_op--;
822 			}
823 
824 			start = block_start_op - op_array->opcodes;
825 			if (start != end) {
826 				emit_live_range_raw(op_array, var_num, kind, start, end);
827 			}
828 
829 			do {
830 				use_opline--;
831 
832 				/* The use might have been optimized away, in which case we will hit the def
833 				 * instead. */
834 				if (use_opline->opcode == ZEND_COPY_TMP && use_opline->result.var == rt_var_num) {
835 					start = def_opline + 1 - op_array->opcodes;
836 					emit_live_range_raw(op_array, var_num, kind, start, end);
837 					return;
838 				}
839 			} while (!(
840 				((use_opline->op1_type & (IS_TMP_VAR|IS_VAR)) && use_opline->op1.var == rt_var_num) ||
841 				((use_opline->op2_type & (IS_TMP_VAR|IS_VAR)) && use_opline->op2.var == rt_var_num)
842 			));
843 
844 			start = def_opline + 1 - op_array->opcodes;
845 			end = use_opline - op_array->opcodes;
846 			emit_live_range_raw(op_array, var_num, kind, start, end);
847 			return;
848 		}
849 	}
850 
851 	emit_live_range_raw(op_array, var_num, kind, start, end);
852 }
853 
is_fake_def(zend_op * opline)854 static bool is_fake_def(zend_op *opline) {
855 	/* These opcodes only modify the result, not create it. */
856 	return opline->opcode == ZEND_ROPE_ADD
857 		|| opline->opcode == ZEND_ADD_ARRAY_ELEMENT
858 		|| opline->opcode == ZEND_ADD_ARRAY_UNPACK;
859 }
860 
keeps_op1_alive(zend_op * opline)861 static bool keeps_op1_alive(zend_op *opline) {
862 	/* These opcodes don't consume their OP1 operand,
863 	 * it is later freed by something else. */
864 	if (opline->opcode == ZEND_CASE
865 	 || opline->opcode == ZEND_CASE_STRICT
866 	 || opline->opcode == ZEND_SWITCH_LONG
867 	 || opline->opcode == ZEND_SWITCH_STRING
868 	 || opline->opcode == ZEND_MATCH
869 	 || opline->opcode == ZEND_FETCH_LIST_R
870 	 || opline->opcode == ZEND_FETCH_LIST_W
871 	 || opline->opcode == ZEND_COPY_TMP) {
872 		return 1;
873 	}
874 	ZEND_ASSERT(opline->opcode != ZEND_FE_FETCH_R
875 		&& opline->opcode != ZEND_FE_FETCH_RW
876 		&& opline->opcode != ZEND_VERIFY_RETURN_TYPE
877 		&& opline->opcode != ZEND_BIND_LEXICAL
878 		&& opline->opcode != ZEND_ROPE_ADD);
879 	return 0;
880 }
881 
882 /* Live ranges must be sorted by increasing start opline */
cmp_live_range(const zend_live_range * a,const zend_live_range * b)883 static int cmp_live_range(const zend_live_range *a, const zend_live_range *b) {
884 	return a->start - b->start;
885 }
swap_live_range(zend_live_range * a,zend_live_range * b)886 static void swap_live_range(zend_live_range *a, zend_live_range *b) {
887 	uint32_t tmp;
888 	tmp = a->var;
889 	a->var = b->var;
890 	b->var = tmp;
891 	tmp = a->start;
892 	a->start = b->start;
893 	b->start = tmp;
894 	tmp = a->end;
895 	a->end = b->end;
896 	b->end = tmp;
897 }
898 
zend_calc_live_ranges(zend_op_array * op_array,zend_needs_live_range_cb needs_live_range)899 static void zend_calc_live_ranges(
900 		zend_op_array *op_array, zend_needs_live_range_cb needs_live_range) {
901 	uint32_t opnum = op_array->last;
902 	zend_op *opline = &op_array->opcodes[opnum];
903 	ALLOCA_FLAG(use_heap)
904 	uint32_t var_offset = op_array->last_var;
905 	uint32_t *last_use = do_alloca(sizeof(uint32_t) * op_array->T, use_heap);
906 	memset(last_use, -1, sizeof(uint32_t) * op_array->T);
907 
908 	ZEND_ASSERT(!op_array->live_range);
909 	while (opnum > 0) {
910 		opnum--;
911 		opline--;
912 
913 		if ((opline->result_type & (IS_TMP_VAR|IS_VAR)) && !is_fake_def(opline)) {
914 			uint32_t var_num = EX_VAR_TO_NUM(opline->result.var) - var_offset;
915 			/* Defs without uses can occur for two reasons: Either because the result is
916 			 * genuinely unused (e.g. omitted FREE opcode for an unused boolean result), or
917 			 * because there are multiple defining opcodes (e.g. JMPZ_EX and QM_ASSIGN), in
918 			 * which case the last one starts the live range. As such, we can simply ignore
919 			 * missing uses here. */
920 			if (EXPECTED(last_use[var_num] != (uint32_t) -1)) {
921 				/* Skip trivial live-range */
922 				if (opnum + 1 != last_use[var_num]) {
923 					uint32_t num;
924 
925 #if 1
926 					/* OP_DATA uses only op1 operand */
927 					ZEND_ASSERT(opline->opcode != ZEND_OP_DATA);
928 					num = opnum;
929 #else
930 					/* OP_DATA is really part of the previous opcode. */
931 					num = opnum - (opline->opcode == ZEND_OP_DATA);
932 #endif
933 					emit_live_range(op_array, var_num, num, last_use[var_num], needs_live_range);
934 				}
935 				last_use[var_num] = (uint32_t) -1;
936 			}
937 		}
938 
939 		if ((opline->op1_type & (IS_TMP_VAR|IS_VAR))) {
940 			uint32_t var_num = EX_VAR_TO_NUM(opline->op1.var) - var_offset;
941 			if (EXPECTED(last_use[var_num] == (uint32_t) -1)) {
942 				if (EXPECTED(!keeps_op1_alive(opline))) {
943 					/* OP_DATA is really part of the previous opcode. */
944 					last_use[var_num] = opnum - (opline->opcode == ZEND_OP_DATA);
945 				}
946 			}
947 		}
948 		if (opline->op2_type & (IS_TMP_VAR|IS_VAR)) {
949 			uint32_t var_num = EX_VAR_TO_NUM(opline->op2.var) - var_offset;
950 			if (UNEXPECTED(opline->opcode == ZEND_FE_FETCH_R
951 					|| opline->opcode == ZEND_FE_FETCH_RW)) {
952 				/* OP2 of FE_FETCH is actually a def, not a use. */
953 				if (last_use[var_num] != (uint32_t) -1) {
954 					if (opnum + 1 != last_use[var_num]) {
955 						emit_live_range(
956 							op_array, var_num, opnum, last_use[var_num], needs_live_range);
957 					}
958 					last_use[var_num] = (uint32_t) -1;
959 				}
960 			} else if (EXPECTED(last_use[var_num] == (uint32_t) -1)) {
961 #if 1
962 				/* OP_DATA uses only op1 operand */
963 				ZEND_ASSERT(opline->opcode != ZEND_OP_DATA);
964 				last_use[var_num] = opnum;
965 #else
966 				/* OP_DATA is really part of the previous opcode. */
967 				last_use[var_num] = opnum - (opline->opcode == ZEND_OP_DATA);
968 #endif
969 			}
970 		}
971 	}
972 
973 	if (op_array->last_live_range > 1) {
974 		zend_live_range *r1 = op_array->live_range;
975 		zend_live_range *r2 = r1 + op_array->last_live_range - 1;
976 
977 		/* In most cases we need just revert the array */
978 		while (r1 < r2) {
979 			swap_live_range(r1, r2);
980 			r1++;
981 			r2--;
982 		}
983 
984 		r1 = op_array->live_range;
985 		r2 = r1 + op_array->last_live_range - 1;
986 		while (r1 < r2) {
987 			if (r1->start > (r1+1)->start) {
988 				zend_sort(r1, r2 - r1 + 1, sizeof(zend_live_range),
989 					(compare_func_t) cmp_live_range, (swap_func_t) swap_live_range);
990 				break;
991 			}
992 			r1++;
993 		}
994 	}
995 
996 	free_alloca(last_use, use_heap);
997 }
998 
zend_recalc_live_ranges(zend_op_array * op_array,zend_needs_live_range_cb needs_live_range)999 ZEND_API void zend_recalc_live_ranges(
1000 		zend_op_array *op_array, zend_needs_live_range_cb needs_live_range) {
1001 	/* We assume that we never create live-ranges where there were none before. */
1002 	ZEND_ASSERT(op_array->live_range);
1003 	efree(op_array->live_range);
1004 	op_array->live_range = NULL;
1005 	op_array->last_live_range = 0;
1006 	zend_calc_live_ranges(op_array, needs_live_range);
1007 }
1008 
pass_two(zend_op_array * op_array)1009 ZEND_API void pass_two(zend_op_array *op_array)
1010 {
1011 	zend_op *opline, *end;
1012 
1013 	if (!ZEND_USER_CODE(op_array->type)) {
1014 		return;
1015 	}
1016 	if (CG(compiler_options) & ZEND_COMPILE_EXTENDED_STMT) {
1017 		zend_update_extended_stmts(op_array);
1018 	}
1019 	if (CG(compiler_options) & ZEND_COMPILE_HANDLE_OP_ARRAY) {
1020 		if (zend_extension_flags & ZEND_EXTENSIONS_HAVE_OP_ARRAY_HANDLER) {
1021 			zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_op_array_handler, op_array);
1022 		}
1023 	}
1024 
1025 	if (CG(context).vars_size != op_array->last_var) {
1026 		op_array->vars = (zend_string**) erealloc(op_array->vars, sizeof(zend_string*)*op_array->last_var);
1027 		CG(context).vars_size = op_array->last_var;
1028 	}
1029 
1030 #if ZEND_USE_ABS_CONST_ADDR
1031 	if (CG(context).opcodes_size != op_array->last) {
1032 		op_array->opcodes = (zend_op *) erealloc(op_array->opcodes, sizeof(zend_op)*op_array->last);
1033 		CG(context).opcodes_size = op_array->last;
1034 	}
1035 	if (CG(context).literals_size != op_array->last_literal) {
1036 		op_array->literals = (zval*)erealloc(op_array->literals, sizeof(zval) * op_array->last_literal);
1037 		CG(context).literals_size = op_array->last_literal;
1038 	}
1039 #else
1040 	op_array->opcodes = (zend_op *) erealloc(op_array->opcodes,
1041 		ZEND_MM_ALIGNED_SIZE_EX(sizeof(zend_op) * op_array->last, 16) +
1042 		sizeof(zval) * op_array->last_literal);
1043 	if (op_array->literals) {
1044 		memcpy(((char*)op_array->opcodes) + ZEND_MM_ALIGNED_SIZE_EX(sizeof(zend_op) * op_array->last, 16),
1045 			op_array->literals, sizeof(zval) * op_array->last_literal);
1046 		efree(op_array->literals);
1047 		op_array->literals = (zval*)(((char*)op_array->opcodes) + ZEND_MM_ALIGNED_SIZE_EX(sizeof(zend_op) * op_array->last, 16));
1048 	}
1049 	CG(context).opcodes_size = op_array->last;
1050 	CG(context).literals_size = op_array->last_literal;
1051 #endif
1052 
1053     op_array->T += ZEND_OBSERVER_ENABLED; // reserve last temporary for observers if enabled
1054 
1055 	/* Needs to be set directly after the opcode/literal reallocation, to ensure destruction
1056 	 * happens correctly if any of the following fixups generate a fatal error. */
1057 	op_array->fn_flags |= ZEND_ACC_DONE_PASS_TWO;
1058 
1059 	opline = op_array->opcodes;
1060 	end = opline + op_array->last;
1061 	while (opline < end) {
1062 		switch (opline->opcode) {
1063 			case ZEND_RECV_INIT:
1064 				{
1065 					zval *val = CT_CONSTANT(opline->op2);
1066 					if (Z_TYPE_P(val) == IS_CONSTANT_AST) {
1067 						uint32_t slot = ZEND_MM_ALIGNED_SIZE_EX(op_array->cache_size, 8);
1068 						Z_CACHE_SLOT_P(val) = slot;
1069 						op_array->cache_size += sizeof(zval);
1070 					}
1071 				}
1072 				break;
1073 			case ZEND_FAST_CALL:
1074 				opline->op1.opline_num = op_array->try_catch_array[opline->op1.num].finally_op;
1075 				ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, opline->op1);
1076 				break;
1077 			case ZEND_BRK:
1078 			case ZEND_CONT:
1079 				{
1080 					uint32_t jmp_target = zend_get_brk_cont_target(op_array, opline);
1081 
1082 					if (op_array->fn_flags & ZEND_ACC_HAS_FINALLY_BLOCK) {
1083 						zend_check_finally_breakout(op_array, opline - op_array->opcodes, jmp_target);
1084 					}
1085 					opline->opcode = ZEND_JMP;
1086 					opline->op1.opline_num = jmp_target;
1087 					opline->op2.num = 0;
1088 					ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, opline->op1);
1089 				}
1090 				break;
1091 			case ZEND_GOTO:
1092 				zend_resolve_goto_label(op_array, opline);
1093 				if (op_array->fn_flags & ZEND_ACC_HAS_FINALLY_BLOCK) {
1094 					zend_check_finally_breakout(op_array, opline - op_array->opcodes, opline->op1.opline_num);
1095 				}
1096 				ZEND_FALLTHROUGH;
1097 			case ZEND_JMP:
1098 				ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, opline->op1);
1099 				break;
1100 			case ZEND_JMPZ:
1101 			case ZEND_JMPNZ:
1102 			case ZEND_JMPZ_EX:
1103 			case ZEND_JMPNZ_EX:
1104 			case ZEND_JMP_SET:
1105 			case ZEND_COALESCE:
1106 			case ZEND_FE_RESET_R:
1107 			case ZEND_FE_RESET_RW:
1108 			case ZEND_JMP_NULL:
1109 				ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, opline->op2);
1110 				break;
1111 			case ZEND_ASSERT_CHECK:
1112 			{
1113 				/* If result of assert is unused, result of check is unused as well */
1114 				zend_op *call = &op_array->opcodes[opline->op2.opline_num - 1];
1115 				if (call->opcode == ZEND_EXT_FCALL_END) {
1116 					call--;
1117 				}
1118 				if (call->result_type == IS_UNUSED) {
1119 					opline->result_type = IS_UNUSED;
1120 				}
1121 				ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, opline->op2);
1122 				break;
1123 			}
1124 			case ZEND_FE_FETCH_R:
1125 			case ZEND_FE_FETCH_RW:
1126 				/* absolute index to relative offset */
1127 				opline->extended_value = ZEND_OPLINE_NUM_TO_OFFSET(op_array, opline, opline->extended_value);
1128 				break;
1129 			case ZEND_CATCH:
1130 				if (!(opline->extended_value & ZEND_LAST_CATCH)) {
1131 					ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, opline->op2);
1132 				}
1133 				break;
1134 			case ZEND_RETURN:
1135 			case ZEND_RETURN_BY_REF:
1136 				if (op_array->fn_flags & ZEND_ACC_GENERATOR) {
1137 					opline->opcode = ZEND_GENERATOR_RETURN;
1138 				}
1139 				break;
1140 			case ZEND_SWITCH_LONG:
1141 			case ZEND_SWITCH_STRING:
1142 			case ZEND_MATCH:
1143 			{
1144 				/* absolute indexes to relative offsets */
1145 				HashTable *jumptable = Z_ARRVAL_P(CT_CONSTANT(opline->op2));
1146 				zval *zv;
1147 				ZEND_HASH_FOREACH_VAL(jumptable, zv) {
1148 					Z_LVAL_P(zv) = ZEND_OPLINE_NUM_TO_OFFSET(op_array, opline, Z_LVAL_P(zv));
1149 				} ZEND_HASH_FOREACH_END();
1150 
1151 				opline->extended_value = ZEND_OPLINE_NUM_TO_OFFSET(op_array, opline, opline->extended_value);
1152 				break;
1153 			}
1154 		}
1155 		if (opline->op1_type == IS_CONST) {
1156 			ZEND_PASS_TWO_UPDATE_CONSTANT(op_array, opline, opline->op1);
1157 		} else if (opline->op1_type & (IS_VAR|IS_TMP_VAR)) {
1158 			opline->op1.var = EX_NUM_TO_VAR(op_array->last_var + opline->op1.var);
1159 		}
1160 		if (opline->op2_type == IS_CONST) {
1161 			ZEND_PASS_TWO_UPDATE_CONSTANT(op_array, opline, opline->op2);
1162 		} else if (opline->op2_type & (IS_VAR|IS_TMP_VAR)) {
1163 			opline->op2.var = EX_NUM_TO_VAR(op_array->last_var + opline->op2.var);
1164 		}
1165 		if (opline->result_type & (IS_VAR|IS_TMP_VAR)) {
1166 			opline->result.var = EX_NUM_TO_VAR(op_array->last_var + opline->result.var);
1167 		}
1168 		ZEND_VM_SET_OPCODE_HANDLER(opline);
1169 		opline++;
1170 	}
1171 
1172 	zend_calc_live_ranges(op_array, NULL);
1173 
1174 	return;
1175 }
1176 
get_unary_op(int opcode)1177 ZEND_API unary_op_type get_unary_op(int opcode)
1178 {
1179 	switch (opcode) {
1180 		case ZEND_BW_NOT:
1181 			return (unary_op_type) bitwise_not_function;
1182 		case ZEND_BOOL_NOT:
1183 			return (unary_op_type) boolean_not_function;
1184 		default:
1185 			return (unary_op_type) NULL;
1186 	}
1187 }
1188 
get_binary_op(int opcode)1189 ZEND_API binary_op_type get_binary_op(int opcode)
1190 {
1191 	switch (opcode) {
1192 		case ZEND_ADD:
1193 			return (binary_op_type) add_function;
1194 		case ZEND_SUB:
1195 			return (binary_op_type) sub_function;
1196 		case ZEND_MUL:
1197 			return (binary_op_type) mul_function;
1198 		case ZEND_POW:
1199 			return (binary_op_type) pow_function;
1200 		case ZEND_DIV:
1201 			return (binary_op_type) div_function;
1202 		case ZEND_MOD:
1203 			return (binary_op_type) mod_function;
1204 		case ZEND_SL:
1205 			return (binary_op_type) shift_left_function;
1206 		case ZEND_SR:
1207 			return (binary_op_type) shift_right_function;
1208 		case ZEND_FAST_CONCAT:
1209 		case ZEND_CONCAT:
1210 			return (binary_op_type) concat_function;
1211 		case ZEND_IS_IDENTICAL:
1212 		case ZEND_CASE_STRICT:
1213 			return (binary_op_type) is_identical_function;
1214 		case ZEND_IS_NOT_IDENTICAL:
1215 			return (binary_op_type) is_not_identical_function;
1216 		case ZEND_IS_EQUAL:
1217 		case ZEND_CASE:
1218 			return (binary_op_type) is_equal_function;
1219 		case ZEND_IS_NOT_EQUAL:
1220 			return (binary_op_type) is_not_equal_function;
1221 		case ZEND_IS_SMALLER:
1222 			return (binary_op_type) is_smaller_function;
1223 		case ZEND_IS_SMALLER_OR_EQUAL:
1224 			return (binary_op_type) is_smaller_or_equal_function;
1225 		case ZEND_SPACESHIP:
1226 			return (binary_op_type) compare_function;
1227 		case ZEND_BW_OR:
1228 			return (binary_op_type) bitwise_or_function;
1229 		case ZEND_BW_AND:
1230 			return (binary_op_type) bitwise_and_function;
1231 		case ZEND_BW_XOR:
1232 			return (binary_op_type) bitwise_xor_function;
1233 		case ZEND_BOOL_XOR:
1234 			return (binary_op_type) boolean_xor_function;
1235 		default:
1236 			ZEND_UNREACHABLE();
1237 			return (binary_op_type) NULL;
1238 	}
1239 }
1240