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