xref: /PHP-7.1/Zend/zend_opcode.c (revision 04c4854f)
1 /*
2    +----------------------------------------------------------------------+
3    | Zend Engine                                                          |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 1998-2018 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@zend.com>                                |
16    |          Zeev Suraski <zeev@zend.com>                                |
17    |          Dmitry Stogov <dmitry@zend.com>                             |
18    +----------------------------------------------------------------------+
19 */
20 
21 /* $Id$ */
22 
23 #include <stdio.h>
24 
25 #include "zend.h"
26 #include "zend_alloc.h"
27 #include "zend_compile.h"
28 #include "zend_extensions.h"
29 #include "zend_API.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 
op_array_alloc_ops(zend_op_array * op_array,uint32_t size)47 static void op_array_alloc_ops(zend_op_array *op_array, uint32_t size)
48 {
49 	op_array->opcodes = erealloc(op_array->opcodes, size * sizeof(zend_op));
50 }
51 
init_op_array(zend_op_array * op_array,zend_uchar type,int initial_ops_size)52 void init_op_array(zend_op_array *op_array, zend_uchar type, int initial_ops_size)
53 {
54 	op_array->type = type;
55 	op_array->arg_flags[0] = 0;
56 	op_array->arg_flags[1] = 0;
57 	op_array->arg_flags[2] = 0;
58 
59 	op_array->refcount = (uint32_t *) emalloc(sizeof(uint32_t));
60 	*op_array->refcount = 1;
61 	op_array->last = 0;
62 	op_array->opcodes = NULL;
63 	op_array_alloc_ops(op_array, initial_ops_size);
64 
65 	op_array->last_var = 0;
66 	op_array->vars = NULL;
67 
68 	op_array->T = 0;
69 
70 	op_array->function_name = NULL;
71 	op_array->filename = zend_get_compiled_filename();
72 	op_array->doc_comment = NULL;
73 
74 	op_array->arg_info = NULL;
75 	op_array->num_args = 0;
76 	op_array->required_num_args = 0;
77 
78 	op_array->scope = NULL;
79 	op_array->prototype = NULL;
80 
81 	op_array->live_range = NULL;
82 	op_array->try_catch_array = NULL;
83 	op_array->last_live_range = 0;
84 
85 	op_array->static_variables = NULL;
86 	op_array->last_try_catch = 0;
87 
88 	op_array->fn_flags = 0;
89 
90 	op_array->early_binding = -1;
91 
92 	op_array->last_literal = 0;
93 	op_array->literals = NULL;
94 
95 	op_array->run_time_cache = NULL;
96 	op_array->cache_size = 0;
97 
98 	memset(op_array->reserved, 0, ZEND_MAX_RESERVED_RESOURCES * sizeof(void*));
99 
100 	if (zend_extension_flags & ZEND_EXTENSIONS_HAVE_OP_ARRAY_CTOR) {
101 		zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_op_array_ctor_handler, op_array);
102 	}
103 }
104 
destroy_zend_function(zend_function * function)105 ZEND_API void destroy_zend_function(zend_function *function)
106 {
107 	if (function->type == ZEND_USER_FUNCTION) {
108 		destroy_op_array(&function->op_array);
109 	} else {
110 		ZEND_ASSERT(function->type == ZEND_INTERNAL_FUNCTION);
111 		ZEND_ASSERT(function->common.function_name);
112 		zend_string_release(function->common.function_name);
113 	}
114 }
115 
zend_function_dtor(zval * zv)116 ZEND_API void zend_function_dtor(zval *zv)
117 {
118 	zend_function *function = Z_PTR_P(zv);
119 
120 	if (function->type == ZEND_USER_FUNCTION) {
121 		ZEND_ASSERT(function->common.function_name);
122 		destroy_op_array(&function->op_array);
123 		/* op_arrays are allocated on arena, so we don't have to free them */
124 	} else {
125 		ZEND_ASSERT(function->type == ZEND_INTERNAL_FUNCTION);
126 		ZEND_ASSERT(function->common.function_name);
127 		zend_string_release(function->common.function_name);
128 		if (!(function->common.fn_flags & ZEND_ACC_ARENA_ALLOCATED)) {
129 			pefree(function, 1);
130 		}
131 	}
132 }
133 
zend_cleanup_op_array_data(zend_op_array * op_array)134 ZEND_API void zend_cleanup_op_array_data(zend_op_array *op_array)
135 {
136 	if (op_array->static_variables &&
137 	    !(GC_FLAGS(op_array->static_variables) & IS_ARRAY_IMMUTABLE)) {
138 		zend_hash_clean(op_array->static_variables);
139 	}
140 }
141 
zend_cleanup_user_class_data(zend_class_entry * ce)142 ZEND_API void zend_cleanup_user_class_data(zend_class_entry *ce)
143 {
144 	/* Clean all parts that can contain run-time data */
145 	/* Note that only run-time accessed data need to be cleaned up, pre-defined data can
146 	   not contain objects and thus are not probelmatic */
147 	if (ce->ce_flags & ZEND_HAS_STATIC_IN_METHODS) {
148 		zend_function *func;
149 
150 		ZEND_HASH_FOREACH_PTR(&ce->function_table, func) {
151 			if (func->type == ZEND_USER_FUNCTION) {
152 				zend_cleanup_op_array_data((zend_op_array *) func);
153 			}
154 		} ZEND_HASH_FOREACH_END();
155 	}
156 	if (ce->static_members_table) {
157 		zval *static_members = ce->static_members_table;
158 		zval *p = static_members;
159 		zval *end = p + ce->default_static_members_count;
160 
161 
162 		ce->default_static_members_count = 0;
163 		ce->default_static_members_table = ce->static_members_table = NULL;
164 		while (p != end) {
165 			i_zval_ptr_dtor(p ZEND_FILE_LINE_CC);
166 			p++;
167 		}
168 		efree(static_members);
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 (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 
179 #ifdef ZTS
180 		CG(static_members_table)[(zend_intptr_t)(ce->static_members_table)] = NULL;
181 #else
182 		ce->static_members_table = NULL;
183 #endif
184 		ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
185 		while (p != end) {
186 			i_zval_ptr_dtor(p ZEND_FILE_LINE_CC);
187 			p++;
188 		}
189 		efree(static_members);
190 	}
191 }
192 
_destroy_zend_class_traits_info(zend_class_entry * ce)193 void _destroy_zend_class_traits_info(zend_class_entry *ce)
194 {
195 	if (ce->num_traits > 0 && ce->traits) {
196 		efree(ce->traits);
197 	}
198 
199 	if (ce->trait_aliases) {
200 		size_t i = 0;
201 		while (ce->trait_aliases[i]) {
202 			if (ce->trait_aliases[i]->trait_method) {
203 				if (ce->trait_aliases[i]->trait_method->method_name) {
204 	 				zend_string_release(ce->trait_aliases[i]->trait_method->method_name);
205 				}
206 				if (ce->trait_aliases[i]->trait_method->class_name) {
207 	 				zend_string_release(ce->trait_aliases[i]->trait_method->class_name);
208 				}
209 				efree(ce->trait_aliases[i]->trait_method);
210 			}
211 
212 			if (ce->trait_aliases[i]->alias) {
213 				zend_string_release(ce->trait_aliases[i]->alias);
214 			}
215 
216 			efree(ce->trait_aliases[i]);
217 			i++;
218 		}
219 
220 		efree(ce->trait_aliases);
221 	}
222 
223 	if (ce->trait_precedences) {
224 		size_t i = 0;
225 
226 		while (ce->trait_precedences[i]) {
227 			zend_string_release(ce->trait_precedences[i]->trait_method->method_name);
228 			zend_string_release(ce->trait_precedences[i]->trait_method->class_name);
229 			efree(ce->trait_precedences[i]->trait_method);
230 
231 			if (ce->trait_precedences[i]->exclude_from_classes) {
232 				size_t j = 0;
233 				zend_trait_precedence *cur_precedence = ce->trait_precedences[i];
234 				while (cur_precedence->exclude_from_classes[j].class_name) {
235 					zend_string_release(cur_precedence->exclude_from_classes[j].class_name);
236 					j++;
237 				}
238 				efree(ce->trait_precedences[i]->exclude_from_classes);
239 			}
240 			efree(ce->trait_precedences[i]);
241 			i++;
242 		}
243 		efree(ce->trait_precedences);
244 	}
245 }
246 
destroy_zend_class(zval * zv)247 ZEND_API void destroy_zend_class(zval *zv)
248 {
249 	zend_property_info *prop_info;
250 	zend_class_entry *ce = Z_PTR_P(zv);
251 
252 	if (--ce->refcount > 0) {
253 		return;
254 	}
255 	switch (ce->type) {
256 		case ZEND_USER_CLASS:
257 			if (ce->default_properties_table) {
258 				zval *p = ce->default_properties_table;
259 				zval *end = p + ce->default_properties_count;
260 
261 				while (p != end) {
262 					i_zval_ptr_dtor(p ZEND_FILE_LINE_CC);
263 					p++;
264 				}
265 				efree(ce->default_properties_table);
266 			}
267 			if (ce->default_static_members_table) {
268 				zval *p = ce->default_static_members_table;
269 				zval *end = p + ce->default_static_members_count;
270 
271 				while (p != end) {
272 					i_zval_ptr_dtor(p ZEND_FILE_LINE_CC);
273 					p++;
274 				}
275 				efree(ce->default_static_members_table);
276 			}
277 			ZEND_HASH_FOREACH_PTR(&ce->properties_info, prop_info) {
278 				if (prop_info->ce == ce || (prop_info->flags & ZEND_ACC_SHADOW)) {
279 					zend_string_release(prop_info->name);
280 					if (prop_info->doc_comment) {
281 						zend_string_release(prop_info->doc_comment);
282 					}
283 				}
284 			} ZEND_HASH_FOREACH_END();
285 			zend_hash_destroy(&ce->properties_info);
286 			zend_string_release(ce->name);
287 			zend_hash_destroy(&ce->function_table);
288 			if (zend_hash_num_elements(&ce->constants_table)) {
289 				zend_class_constant *c;
290 
291 				ZEND_HASH_FOREACH_PTR(&ce->constants_table, c) {
292 					if (c->ce == ce) {
293 						zval_ptr_dtor(&c->value);
294 						if (c->doc_comment) {
295 							zend_string_release(c->doc_comment);
296 						}
297 					}
298 				} ZEND_HASH_FOREACH_END();
299 			}
300 			zend_hash_destroy(&ce->constants_table);
301 			if (ce->num_interfaces > 0 && ce->interfaces) {
302 				efree(ce->interfaces);
303 			}
304 			if (ce->info.user.doc_comment) {
305 				zend_string_release(ce->info.user.doc_comment);
306 			}
307 
308 			_destroy_zend_class_traits_info(ce);
309 
310 			break;
311 		case ZEND_INTERNAL_CLASS:
312 			if (ce->default_properties_table) {
313 				zval *p = ce->default_properties_table;
314 				zval *end = p + ce->default_properties_count;
315 
316 				while (p != end) {
317 					zval_internal_ptr_dtor(p);
318 					p++;
319 				}
320 				free(ce->default_properties_table);
321 			}
322 			if (ce->default_static_members_table) {
323 				zval *p = ce->default_static_members_table;
324 				zval *end = p + ce->default_static_members_count;
325 
326 				while (p != end) {
327 					zval_internal_ptr_dtor(p);
328 					p++;
329 				}
330 				free(ce->default_static_members_table);
331 			}
332 			zend_hash_destroy(&ce->properties_info);
333 			zend_string_release(ce->name);
334 			zend_hash_destroy(&ce->function_table);
335 			if (zend_hash_num_elements(&ce->constants_table)) {
336 				zend_class_constant *c;
337 
338 				ZEND_HASH_FOREACH_PTR(&ce->constants_table, c) {
339 					zval_internal_ptr_dtor(&c->value);
340 					if (c->doc_comment && c->ce == ce) {
341 						zend_string_release(c->doc_comment);
342 					}
343 				} ZEND_HASH_FOREACH_END();
344 				zend_hash_destroy(&ce->constants_table);
345 			}
346 			if (ce->num_interfaces > 0) {
347 				free(ce->interfaces);
348 			}
349 			free(ce);
350 			break;
351 	}
352 }
353 
zend_class_add_ref(zval * zv)354 void zend_class_add_ref(zval *zv)
355 {
356 	zend_class_entry *ce = Z_PTR_P(zv);
357 
358 	ce->refcount++;
359 }
360 
destroy_op_array(zend_op_array * op_array)361 ZEND_API void destroy_op_array(zend_op_array *op_array)
362 {
363 	zval *literal = op_array->literals;
364 	zval *end;
365 	uint32_t i;
366 
367 	if (op_array->static_variables &&
368 	    !(GC_FLAGS(op_array->static_variables) & IS_ARRAY_IMMUTABLE)) {
369 		if (--GC_REFCOUNT(op_array->static_variables) == 0) {
370 			zend_array_destroy(op_array->static_variables);
371 		}
372 	}
373 
374 	if (op_array->run_time_cache && !op_array->function_name) {
375 		efree(op_array->run_time_cache);
376 		op_array->run_time_cache = NULL;
377 	}
378 
379 	if (!op_array->refcount || --(*op_array->refcount) > 0) {
380 		return;
381 	}
382 
383 	efree_size(op_array->refcount, sizeof(*(op_array->refcount)));
384 
385 	if (op_array->vars) {
386 		i = op_array->last_var;
387 		while (i > 0) {
388 			i--;
389 			zend_string_release(op_array->vars[i]);
390 		}
391 		efree(op_array->vars);
392 	}
393 
394 	if (literal) {
395 	 	end = literal + op_array->last_literal;
396 	 	while (literal < end) {
397 			zval_ptr_dtor_nogc(literal);
398 			literal++;
399 		}
400 		efree(op_array->literals);
401 	}
402 	efree(op_array->opcodes);
403 
404 	if (op_array->function_name) {
405 		zend_string_release(op_array->function_name);
406 	}
407 	if (op_array->doc_comment) {
408 		zend_string_release(op_array->doc_comment);
409 	}
410 	if (op_array->live_range) {
411 		efree(op_array->live_range);
412 	}
413 	if (op_array->try_catch_array) {
414 		efree(op_array->try_catch_array);
415 	}
416 	if (zend_extension_flags & ZEND_EXTENSIONS_HAVE_OP_ARRAY_DTOR) {
417 		if (op_array->fn_flags & ZEND_ACC_DONE_PASS_TWO) {
418 			zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_op_array_dtor_handler, op_array);
419 		}
420 	}
421 	if (op_array->arg_info) {
422 		uint32_t num_args = op_array->num_args;
423 		zend_arg_info *arg_info = op_array->arg_info;
424 
425 		if (op_array->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
426 			arg_info--;
427 			num_args++;
428 		}
429 		if (op_array->fn_flags & ZEND_ACC_VARIADIC) {
430 			num_args++;
431 		}
432 		for (i = 0 ; i < num_args; i++) {
433 			if (arg_info[i].name) {
434 				zend_string_release(arg_info[i].name);
435 			}
436 			if (arg_info[i].class_name) {
437 				zend_string_release(arg_info[i].class_name);
438 			}
439 		}
440 		efree(arg_info);
441 	}
442 }
443 
init_op(zend_op * op)444 void init_op(zend_op *op)
445 {
446 	memset(op, 0, sizeof(zend_op));
447 	op->lineno = CG(zend_lineno);
448 	SET_UNUSED(op->result);
449 }
450 
get_next_op(zend_op_array * op_array)451 zend_op *get_next_op(zend_op_array *op_array)
452 {
453 	uint32_t next_op_num = op_array->last++;
454 	zend_op *next_op;
455 
456 	if (next_op_num >= CG(context).opcodes_size) {
457 		CG(context).opcodes_size *= 4;
458 		op_array_alloc_ops(op_array, CG(context).opcodes_size);
459 	}
460 
461 	next_op = &(op_array->opcodes[next_op_num]);
462 
463 	init_op(next_op);
464 
465 	return next_op;
466 }
467 
get_next_op_number(zend_op_array * op_array)468 uint32_t get_next_op_number(zend_op_array *op_array)
469 {
470 	return op_array->last;
471 }
472 
get_next_brk_cont_element(void)473 zend_brk_cont_element *get_next_brk_cont_element(void)
474 {
475 	CG(context).last_brk_cont++;
476 	CG(context).brk_cont_array = erealloc(CG(context).brk_cont_array, sizeof(zend_brk_cont_element) * CG(context).last_brk_cont);
477 	return &CG(context).brk_cont_array[CG(context).last_brk_cont-1];
478 }
479 
zend_update_extended_info(zend_op_array * op_array)480 static void zend_update_extended_info(zend_op_array *op_array)
481 {
482 	zend_op *opline = op_array->opcodes, *end=opline+op_array->last;
483 
484 	while (opline<end) {
485 		if (opline->opcode == ZEND_EXT_STMT) {
486 			if (opline+1<end) {
487 				if ((opline+1)->opcode == ZEND_EXT_STMT) {
488 					opline->opcode = ZEND_NOP;
489 					opline++;
490 					continue;
491 				}
492 				if (opline+1<end) {
493 					opline->lineno = (opline+1)->lineno;
494 				}
495 			} else {
496 				opline->opcode = ZEND_NOP;
497 			}
498 		}
499 		opline++;
500 	}
501 }
502 
zend_extension_op_array_handler(zend_extension * extension,zend_op_array * op_array)503 static void zend_extension_op_array_handler(zend_extension *extension, zend_op_array *op_array)
504 {
505 	if (extension->op_array_handler) {
506 		extension->op_array_handler(op_array);
507 	}
508 }
509 
zend_check_finally_breakout(zend_op_array * op_array,uint32_t op_num,uint32_t dst_num)510 static void zend_check_finally_breakout(zend_op_array *op_array, uint32_t op_num, uint32_t dst_num)
511 {
512 	int i;
513 
514 	for (i = 0; i < op_array->last_try_catch; i++) {
515 		if ((op_num < op_array->try_catch_array[i].finally_op ||
516 					op_num >= op_array->try_catch_array[i].finally_end)
517 				&& (dst_num >= op_array->try_catch_array[i].finally_op &&
518 					 dst_num <= op_array->try_catch_array[i].finally_end)) {
519 			CG(in_compilation) = 1;
520 			CG(active_op_array) = op_array;
521 			CG(zend_lineno) = op_array->opcodes[op_num].lineno;
522 			zend_error_noreturn(E_COMPILE_ERROR, "jump into a finally block is disallowed");
523 		} else if ((op_num >= op_array->try_catch_array[i].finally_op
524 					&& op_num <= op_array->try_catch_array[i].finally_end)
525 				&& (dst_num > op_array->try_catch_array[i].finally_end
526 					|| dst_num < op_array->try_catch_array[i].finally_op)) {
527 			CG(in_compilation) = 1;
528 			CG(active_op_array) = op_array;
529 			CG(zend_lineno) = op_array->opcodes[op_num].lineno;
530 			zend_error_noreturn(E_COMPILE_ERROR, "jump out of a finally block is disallowed");
531 		}
532 	}
533 }
534 
zend_get_brk_cont_target(const zend_op_array * op_array,const zend_op * opline)535 static uint32_t zend_get_brk_cont_target(const zend_op_array *op_array, const zend_op *opline) {
536 	int nest_levels = opline->op2.num;
537 	int array_offset = opline->op1.num;
538 	zend_brk_cont_element *jmp_to;
539 	do {
540 		jmp_to = &CG(context).brk_cont_array[array_offset];
541 		if (nest_levels > 1) {
542 			array_offset = jmp_to->parent;
543 		}
544 	} while (--nest_levels > 0);
545 
546 	return opline->opcode == ZEND_BRK ? jmp_to->brk : jmp_to->cont;
547 }
548 
pass_two(zend_op_array * op_array)549 ZEND_API int pass_two(zend_op_array *op_array)
550 {
551 	zend_op *opline, *end;
552 
553 	if (!ZEND_USER_CODE(op_array->type)) {
554 		return 0;
555 	}
556 	if (CG(compiler_options) & ZEND_COMPILE_EXTENDED_INFO) {
557 		zend_update_extended_info(op_array);
558 	}
559 	if (CG(compiler_options) & ZEND_COMPILE_HANDLE_OP_ARRAY) {
560 		if (zend_extension_flags & ZEND_EXTENSIONS_HAVE_OP_ARRAY_HANDLER) {
561 			zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_op_array_handler, op_array);
562 		}
563 	}
564 
565 	if (CG(context).vars_size != op_array->last_var) {
566 		op_array->vars = (zend_string**) erealloc(op_array->vars, sizeof(zend_string*)*op_array->last_var);
567 		CG(context).vars_size = op_array->last_var;
568 	}
569 	if (CG(context).opcodes_size != op_array->last) {
570 		op_array->opcodes = (zend_op *) erealloc(op_array->opcodes, sizeof(zend_op)*op_array->last);
571 		CG(context).opcodes_size = op_array->last;
572 	}
573 	if (CG(context).literals_size != op_array->last_literal) {
574 		op_array->literals = (zval*)erealloc(op_array->literals, sizeof(zval) * op_array->last_literal);
575 		CG(context).literals_size = op_array->last_literal;
576 	}
577 	opline = op_array->opcodes;
578 	end = opline + op_array->last;
579 	while (opline < end) {
580 		switch (opline->opcode) {
581 			case ZEND_FAST_CALL:
582 				opline->op1.opline_num = op_array->try_catch_array[opline->op1.num].finally_op;
583 				ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, opline->op1);
584 				break;
585 			case ZEND_BRK:
586 			case ZEND_CONT:
587 				{
588 					uint32_t jmp_target = zend_get_brk_cont_target(op_array, opline);
589 
590 					if (op_array->fn_flags & ZEND_ACC_HAS_FINALLY_BLOCK) {
591 						zend_check_finally_breakout(op_array, opline - op_array->opcodes, jmp_target);
592 					}
593 					opline->opcode = ZEND_JMP;
594 					opline->op1.opline_num = jmp_target;
595 					opline->op2.num = 0;
596 					ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, opline->op1);
597 				}
598 				break;
599 			case ZEND_GOTO:
600 				zend_resolve_goto_label(op_array, opline);
601 				if (op_array->fn_flags & ZEND_ACC_HAS_FINALLY_BLOCK) {
602 					zend_check_finally_breakout(op_array, opline - op_array->opcodes, opline->op1.opline_num);
603 				}
604 				/* break omitted intentionally */
605 			case ZEND_JMP:
606 				ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, opline->op1);
607 				break;
608 			case ZEND_JMPZNZ:
609 				/* absolute index to relative offset */
610 				opline->extended_value = ZEND_OPLINE_NUM_TO_OFFSET(op_array, opline, opline->extended_value);
611 				/* break omitted intentionally */
612 			case ZEND_JMPZ:
613 			case ZEND_JMPNZ:
614 			case ZEND_JMPZ_EX:
615 			case ZEND_JMPNZ_EX:
616 			case ZEND_JMP_SET:
617 			case ZEND_COALESCE:
618 			case ZEND_FE_RESET_R:
619 			case ZEND_FE_RESET_RW:
620 				ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, opline->op2);
621 				break;
622 			case ZEND_ASSERT_CHECK:
623 			{
624 				/* If result of assert is unused, result of check is unused as well */
625 				zend_op *call = &op_array->opcodes[opline->op2.opline_num - 1];
626 				if (call->opcode == ZEND_EXT_FCALL_END) {
627 					call--;
628 				}
629 				if (call->result_type == IS_UNUSED) {
630 					opline->result_type = IS_UNUSED;
631 				}
632 				ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, opline->op2);
633 				break;
634 			}
635 			case ZEND_DECLARE_ANON_CLASS:
636 			case ZEND_DECLARE_ANON_INHERITED_CLASS:
637 			case ZEND_CATCH:
638 			case ZEND_FE_FETCH_R:
639 			case ZEND_FE_FETCH_RW:
640 				/* absolute index to relative offset */
641 				opline->extended_value = ZEND_OPLINE_NUM_TO_OFFSET(op_array, opline, opline->extended_value);
642 				break;
643 			case ZEND_RETURN:
644 			case ZEND_RETURN_BY_REF:
645 				if (op_array->fn_flags & ZEND_ACC_GENERATOR) {
646 					opline->opcode = ZEND_GENERATOR_RETURN;
647 				}
648 				break;
649 		}
650 		if (opline->op1_type == IS_CONST) {
651 			ZEND_PASS_TWO_UPDATE_CONSTANT(op_array, opline->op1);
652 		} else if (opline->op1_type & (IS_VAR|IS_TMP_VAR)) {
653 			opline->op1.var = (uint32_t)(zend_intptr_t)ZEND_CALL_VAR_NUM(NULL, op_array->last_var + opline->op1.var);
654 		}
655 		if (opline->op2_type == IS_CONST) {
656 			ZEND_PASS_TWO_UPDATE_CONSTANT(op_array, opline->op2);
657 		} else if (opline->op2_type & (IS_VAR|IS_TMP_VAR)) {
658 			opline->op2.var = (uint32_t)(zend_intptr_t)ZEND_CALL_VAR_NUM(NULL, op_array->last_var + opline->op2.var);
659 		}
660 		if (opline->result_type & (IS_VAR|IS_TMP_VAR)) {
661 			opline->result.var = (uint32_t)(zend_intptr_t)ZEND_CALL_VAR_NUM(NULL, op_array->last_var + opline->result.var);
662 		}
663 		ZEND_VM_SET_OPCODE_HANDLER(opline);
664 		opline++;
665 	}
666 
667 	if (op_array->live_range) {
668 		int i;
669 
670 		for (i = 0; i < op_array->last_live_range; i++) {
671 			op_array->live_range[i].var =
672 				(uint32_t)(zend_intptr_t)ZEND_CALL_VAR_NUM(NULL, op_array->last_var + (op_array->live_range[i].var / sizeof(zval))) |
673 				(op_array->live_range[i].var & ZEND_LIVE_MASK);
674 		}
675 	}
676 
677 	op_array->fn_flags |= ZEND_ACC_DONE_PASS_TWO;
678 	return 0;
679 }
680 
get_unary_op(int opcode)681 ZEND_API unary_op_type get_unary_op(int opcode)
682 {
683 	switch (opcode) {
684 		case ZEND_BW_NOT:
685 			return (unary_op_type) bitwise_not_function;
686 		case ZEND_BOOL_NOT:
687 			return (unary_op_type) boolean_not_function;
688 		default:
689 			return (unary_op_type) NULL;
690 	}
691 }
692 
get_binary_op(int opcode)693 ZEND_API binary_op_type get_binary_op(int opcode)
694 {
695 	switch (opcode) {
696 		case ZEND_ADD:
697 		case ZEND_ASSIGN_ADD:
698 			return (binary_op_type) add_function;
699 		case ZEND_SUB:
700 		case ZEND_ASSIGN_SUB:
701 			return (binary_op_type) sub_function;
702 		case ZEND_MUL:
703 		case ZEND_ASSIGN_MUL:
704 			return (binary_op_type) mul_function;
705 		case ZEND_POW:
706 			return (binary_op_type) pow_function;
707 		case ZEND_DIV:
708 		case ZEND_ASSIGN_DIV:
709 			return (binary_op_type) div_function;
710 		case ZEND_MOD:
711 		case ZEND_ASSIGN_MOD:
712 			return (binary_op_type) mod_function;
713 		case ZEND_SL:
714 		case ZEND_ASSIGN_SL:
715 			return (binary_op_type) shift_left_function;
716 		case ZEND_SR:
717 		case ZEND_ASSIGN_SR:
718 			return (binary_op_type) shift_right_function;
719 		case ZEND_FAST_CONCAT:
720 		case ZEND_CONCAT:
721 		case ZEND_ASSIGN_CONCAT:
722 			return (binary_op_type) concat_function;
723 		case ZEND_IS_IDENTICAL:
724 			return (binary_op_type) is_identical_function;
725 		case ZEND_IS_NOT_IDENTICAL:
726 			return (binary_op_type) is_not_identical_function;
727 		case ZEND_IS_EQUAL:
728 			return (binary_op_type) is_equal_function;
729 		case ZEND_IS_NOT_EQUAL:
730 			return (binary_op_type) is_not_equal_function;
731 		case ZEND_IS_SMALLER:
732 			return (binary_op_type) is_smaller_function;
733 		case ZEND_IS_SMALLER_OR_EQUAL:
734 			return (binary_op_type) is_smaller_or_equal_function;
735 		case ZEND_SPACESHIP:
736 			return (binary_op_type) compare_function;
737 		case ZEND_BW_OR:
738 		case ZEND_ASSIGN_BW_OR:
739 			return (binary_op_type) bitwise_or_function;
740 		case ZEND_BW_AND:
741 		case ZEND_ASSIGN_BW_AND:
742 			return (binary_op_type) bitwise_and_function;
743 		case ZEND_BW_XOR:
744 		case ZEND_ASSIGN_BW_XOR:
745 			return (binary_op_type) bitwise_xor_function;
746 		case ZEND_BOOL_XOR:
747 			return (binary_op_type) boolean_xor_function;
748 		default:
749 			return (binary_op_type) NULL;
750 	}
751 }
752 
753 /*
754  * Local variables:
755  * tab-width: 4
756  * c-basic-offset: 4
757  * indent-tabs-mode: t
758  * End:
759  */
760