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