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