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