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