]> granicus.if.org Git - php/blob - ext/opcache/jit/zend_jit_disasm_x86.c
6a9892bafcdea700d4fad09189d0b940edda3eea
[php] / ext / opcache / jit / zend_jit_disasm_x86.c
1 /*
2    +----------------------------------------------------------------------+
3    | Zend JIT                                                             |
4    +----------------------------------------------------------------------+
5    | Copyright (c) The PHP Group                                          |
6    +----------------------------------------------------------------------+
7    | This source file is subject to version 3.01 of the PHP 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.php.net/license/3_01.txt                                  |
11    | If you did not receive a copy of the PHP license and are unable to   |
12    | obtain it through the world-wide-web, please send a note to          |
13    | license@php.net so we can mail you a copy immediately.               |
14    +----------------------------------------------------------------------+
15    | Authors: Dmitry Stogov <dmitry@php.net>                              |
16    |          Xinchen Hui <laruence@php.net>                              |
17    +----------------------------------------------------------------------+
18 */
19
20 #define HAVE_DISASM 1
21 #define DISASM_INTEL_SYNTAX 0
22
23 #include "jit/libudis86/itab.c"
24 #include "jit/libudis86/decode.c"
25 #include "jit/libudis86/syn.c"
26 #if DISASM_INTEL_SYNTAX
27 # include "jit/libudis86/syn-intel.c"
28 #else
29 # include "jit/libudis86/syn-att.c"
30 #endif
31 #include "jit/libudis86/udis86.c"
32
33 static void zend_jit_disasm_add_symbol(const char *name,
34                                        uint64_t    addr,
35                                        uint64_t    size);
36
37 #ifndef _WIN32
38 # include "jit/zend_elf.c"
39 #endif
40
41 #include "zend_sort.h"
42
43 #ifndef _GNU_SOURCE
44 # define _GNU_SOURCE
45 #endif
46
47 #ifndef _WIN32
48 #include <dlfcn.h>
49 #endif
50
51 static struct ud ud;
52
53 struct _sym_node {
54         uint64_t          addr;
55         uint64_t          end;
56         struct _sym_node *parent;
57         struct _sym_node *child[2];
58         unsigned char     info;
59         char              name[1];
60 };
61
62 static void zend_syms_rotateleft(zend_sym_node *p) {
63         zend_sym_node *r = p->child[1];
64         p->child[1] = r->child[0];
65         if (r->child[0]) {
66                 r->child[0]->parent = p;
67         }
68         r->parent = p->parent;
69         if (p->parent == NULL) {
70                 JIT_G(symbols) = r;
71         } else if (p->parent->child[0] == p) {
72                 p->parent->child[0] = r;
73         } else {
74                 p->parent->child[1] = r;
75         }
76         r->child[0] = p;
77         p->parent = r;
78 }
79
80 static void zend_syms_rotateright(zend_sym_node *p) {
81         zend_sym_node *l = p->child[0];
82         p->child[0] = l->child[1];
83         if (l->child[1]) {
84                 l->child[1]->parent = p;
85         }
86         l->parent = p->parent;
87         if (p->parent == NULL) {
88                 JIT_G(symbols) = l;
89         } else if (p->parent->child[1] == p) {
90                 p->parent->child[1] = l;
91         } else {
92                 p->parent->child[0] = l;
93         }
94         l->child[1] = p;
95         p->parent = l;
96 }
97
98 static void zend_jit_disasm_add_symbol(const char *name,
99                                        uint64_t    addr,
100                                        uint64_t    size)
101 {
102         zend_sym_node *sym;
103         size_t len = strlen(name);
104
105         sym = malloc(sizeof(zend_sym_node) + len + 1);
106         if (!sym) {
107                 return;
108         }
109         sym->addr = addr;
110         sym->end  = (addr + size - 1);
111         memcpy((char*)&sym->name, name, len + 1);
112         sym->parent = sym->child[0] = sym->child[1] = NULL;
113         sym->info = 1;
114         if (JIT_G(symbols)) {
115                 zend_sym_node *node = JIT_G(symbols);
116
117                 /* insert it into rbtree */
118                 do {
119                         if (sym->addr > node->addr) {
120                                 ZEND_ASSERT(sym->addr > (node->end));
121                                 if (node->child[1]) {
122                                         node = node->child[1];
123                                 } else {
124                                         node->child[1] = sym;
125                                         sym->parent = node;
126                                         break;
127                                 }
128                         } else if (sym->addr < node->addr) {
129                                 if (node->child[0]) {
130                                         node = node->child[0];
131                                 } else {
132                                         node->child[0] = sym;
133                                         sym->parent = node;
134                                         break;
135                                 }
136                         } else {
137                                 ZEND_ASSERT(sym->addr == node->addr);
138                                 if (strcmp(name, node->name) == 0 && sym->end < node->end) {
139                                         /* reduce size of the existing symbol */
140                                         node->end = sym->end;
141                                 }
142                                 free(sym);
143                                 return;
144                         }
145                 } while (1);
146
147                 /* fix rbtree after instering */
148                 while (sym && sym != JIT_G(symbols) && sym->parent->info == 1) {
149                         if (sym->parent == sym->parent->parent->child[0]) {
150                                 node = sym->parent->parent->child[1];
151                                 if (node && node->info == 1) {
152                                         sym->parent->info = 0;
153                                         node->info = 0;
154                                         sym->parent->parent->info = 1;
155                                         sym = sym->parent->parent;
156                                 } else {
157                                         if (sym == sym->parent->child[1]) {
158                                                 sym = sym->parent;
159                                                 zend_syms_rotateleft(sym);
160                                         }
161                                         sym->parent->info = 0;
162                                         sym->parent->parent->info = 1;
163                                         zend_syms_rotateright(sym->parent->parent);
164                                 }
165                         } else {
166                                 node = sym->parent->parent->child[0];
167                                 if (node && node->info == 1) {
168                                         sym->parent->info = 0;
169                                         node->info = 0;
170                                         sym->parent->parent->info = 1;
171                                         sym = sym->parent->parent;
172                                 } else {
173                                         if (sym == sym->parent->child[0]) {
174                                                 sym = sym->parent;
175                                                 zend_syms_rotateright(sym);
176                                         }
177                                         sym->parent->info = 0;
178                                         sym->parent->parent->info = 1;
179                                         zend_syms_rotateleft(sym->parent->parent);
180                                 }
181                         }
182                 }
183         } else {
184                 JIT_G(symbols) = sym;
185         }
186         JIT_G(symbols)->info = 0;
187 }
188
189 static void zend_jit_disasm_destroy_symbols(zend_sym_node *n) {
190         if (n) {
191                 if (n->child[0]) {
192                         zend_jit_disasm_destroy_symbols(n->child[0]);
193                 }
194                 if (n->child[1]) {
195                         zend_jit_disasm_destroy_symbols(n->child[1]);
196                 }
197                 free(n);
198         }
199 }
200
201 static const char* zend_jit_disasm_find_symbol(uint64_t  addr,
202                                                int64_t  *offset) {
203         zend_sym_node *node = JIT_G(symbols);
204         while (node) {
205                 if (addr < node->addr) {
206                         node = node->child[0];
207                 } else if (addr > node->end) {
208                         node = node->child[1];
209                 } else {
210                         *offset = addr - node->addr;
211                         return node->name;
212                 }
213         }
214         return NULL;
215 }
216
217 static const char* zend_jit_disasm_resolver(struct ud *ud,
218                                             uint64_t   addr,
219                                             int64_t   *offset)
220 {
221 #ifndef _WIN32
222         ((void)ud);
223         const char *name;
224         void *a = (void*)(zend_uintptr_t)(addr);
225         Dl_info info;
226
227         name = zend_jit_disasm_find_symbol(addr, offset);
228         if (name) {
229                 return name;
230         }
231
232         if (dladdr(a, &info)
233          && info.dli_sname != NULL
234          && info.dli_saddr == a) {
235                 return info.dli_sname;
236         }
237 #else
238         const char *name;
239         name = zend_jit_disasm_find_symbol(addr, offset);
240         if (name) {
241                 return name;
242         }
243 #endif
244
245         return NULL;
246 }
247
248 static int zend_jit_cmp_labels(Bucket *b1, Bucket *b2)
249 {
250         return ((b1->h > b2->h) > 0) ? 1 : -1;
251 }
252
253 static int zend_jit_disasm(const char    *name,
254                            const char    *filename,
255                            const zend_op_array *op_array,
256                            zend_cfg      *cfg,
257                            const void    *start,
258                            size_t         size)
259 {
260         const void *end = (void *)((char *)start + size);
261         zval zv, *z;
262         zend_long n, m;
263         HashTable labels;
264         const struct ud_operand *op;
265         uint64_t addr;
266         int b;
267
268         if (name) {
269                 fprintf(stderr, "%s: ; (%s)\n", name, filename ? filename : "unknown");
270         }
271
272         ud_set_input_buffer(&ud, (uint8_t*)start, (uint8_t*)end - (uint8_t*)start);
273         ud_set_pc(&ud, (uint64_t)(uintptr_t)start);
274
275         zend_hash_init(&labels, 8, NULL, NULL, 0);
276         if (op_array && cfg) {
277                 ZVAL_FALSE(&zv);
278                 for (b = 0; b < cfg->blocks_count; b++) {
279                         if (cfg->blocks[b].flags & (ZEND_BB_ENTRY|ZEND_BB_RECV_ENTRY)) {
280                                 addr = (uint64_t)(uintptr_t)op_array->opcodes[cfg->blocks[b].start].handler;
281                                 if (addr >= (uint64_t)(uintptr_t)start && addr < (uint64_t)(uintptr_t)end) {
282                                         zend_hash_index_add(&labels, addr, &zv);
283                                 }
284                         }
285                 }
286         }
287         ZVAL_TRUE(&zv);
288         while (ud_disassemble(&ud)) {
289                 op = ud_insn_opr(&ud, 0);
290                 if (op && op->type == UD_OP_JIMM) {
291                         addr = ud_syn_rel_target(&ud, (struct ud_operand*)op);
292                         if (addr >= (uint64_t)(uintptr_t)start && addr < (uint64_t)(uintptr_t)end) {
293                                 zend_hash_index_add(&labels, addr, &zv);
294                         }
295                 }
296         }
297
298         zend_hash_sort(&labels, zend_jit_cmp_labels, 0);
299
300         /* label numbering */
301         n = 0; m = 0;
302         ZEND_HASH_FOREACH_VAL(&labels, z) {
303                 if (Z_TYPE_P(z) == IS_FALSE) {
304                         m--;
305                         ZVAL_LONG(z, m);
306                 } else {
307                         n++;
308                         ZVAL_LONG(z, n);
309                 }
310         } ZEND_HASH_FOREACH_END();
311
312         ud_set_input_buffer(&ud, (uint8_t*)start, (uint8_t*)end - (uint8_t*)start);
313         ud_set_pc(&ud, (uint64_t)(uintptr_t)start);
314
315         while (ud_disassemble(&ud)) {
316                 addr = ud_insn_off(&ud);
317                 z = zend_hash_index_find(&labels, addr);
318                 if (z) {
319                         if (Z_LVAL_P(z) < 0) {
320                                 fprintf(stderr, ".ENTRY" ZEND_LONG_FMT ":\n", -Z_LVAL_P(z));
321                         } else {
322                                 fprintf(stderr, ".L" ZEND_LONG_FMT ":\n", Z_LVAL_P(z));
323                         }
324                 }
325                 op = ud_insn_opr(&ud, 0);
326                 if (op && op->type == UD_OP_JIMM) {
327                         addr = ud_syn_rel_target(&ud, (struct ud_operand*)op);
328                         if (addr >= (uint64_t)(uintptr_t)start && addr < (uint64_t)(uintptr_t)end) {
329                                 z = zend_hash_index_find(&labels, addr);
330                                 if (z) {
331                                         const char *str = ud_insn_asm(&ud);
332                                         int len;
333
334                                         len = 0;
335                                         while (str[len] != 0 && str[len] != ' ' && str[len] != '\t') {
336                                                 len++;
337                                         }
338                                         if (str[len] != 0) {
339                                                 while (str[len] == ' ' || str[len] == '\t') {
340                                                         len++;
341                                                 }
342                                                 if (Z_LVAL_P(z) < 0) {
343                                                         fprintf(stderr, "\t%.*s.ENTRY" ZEND_LONG_FMT "\n", len, str, -Z_LVAL_P(z));
344                                                 } else {
345                                                         fprintf(stderr, "\t%.*s.L" ZEND_LONG_FMT "\n", len, str, Z_LVAL_P(z));
346                                                 }
347                                                 continue;
348                                         }
349                                 }
350                         }
351                 }
352                 fprintf(stderr, "\t%s\n", ud_insn_asm(&ud));
353         }
354         fprintf(stderr, "\n");
355
356         zend_hash_destroy(&labels);
357
358         return 1;
359 }
360
361 static int zend_jit_disasm_init(void)
362 {
363         ud_init(&ud);
364 #if defined(__x86_64__) || defined(_WIN64)
365         ud_set_mode(&ud, 64);
366 #else
367         ud_set_mode(&ud, 32);
368 #endif
369 #if DISASM_INTEL_SYNTAX
370         ud_set_syntax(&ud, UD_SYN_INTEL);
371 #else
372         ud_set_syntax(&ud, UD_SYN_ATT);
373 #endif
374         ud_set_sym_resolver(&ud, zend_jit_disasm_resolver);
375
376 #ifndef ZTS
377 #define REGISTER_EG(n)  \
378         zend_jit_disasm_add_symbol("EG("#n")", \
379                 (uint64_t)(uintptr_t)&executor_globals.n, sizeof(executor_globals.n))
380         REGISTER_EG(uninitialized_zval);
381         REGISTER_EG(exception);
382         REGISTER_EG(vm_interrupt);
383         REGISTER_EG(exception_op);
384         REGISTER_EG(timed_out);
385         REGISTER_EG(current_execute_data);
386         REGISTER_EG(vm_stack_top);
387         REGISTER_EG(vm_stack_end);
388         REGISTER_EG(symbol_table);
389         REGISTER_EG(jit_trace_num);
390 #undef  REGISTER_EG
391 #endif
392
393         /* Register JIT helper functions */
394 #define REGISTER_HELPER(n)  \
395         zend_jit_disasm_add_symbol(#n, \
396                 (uint64_t)(uintptr_t)n, sizeof(void*));
397         REGISTER_HELPER(memcmp);
398         REGISTER_HELPER(zend_jit_init_func_run_time_cache_helper);
399         REGISTER_HELPER(zend_jit_find_func_helper);
400         REGISTER_HELPER(zend_jit_find_ns_func_helper);
401         REGISTER_HELPER(zend_jit_find_method_helper);
402         REGISTER_HELPER(zend_jit_find_method_tmp_helper);
403         REGISTER_HELPER(zend_jit_push_static_metod_call_frame);
404         REGISTER_HELPER(zend_jit_push_static_metod_call_frame_tmp);
405         REGISTER_HELPER(zend_jit_invalid_method_call);
406         REGISTER_HELPER(zend_jit_invalid_method_call_tmp);
407         REGISTER_HELPER(zend_jit_unref_helper);
408         REGISTER_HELPER(zend_jit_extend_stack_helper);
409         REGISTER_HELPER(zend_jit_int_extend_stack_helper);
410         REGISTER_HELPER(zend_jit_leave_nested_func_helper);
411         REGISTER_HELPER(zend_jit_leave_top_func_helper);
412         REGISTER_HELPER(zend_jit_leave_func_helper);
413         REGISTER_HELPER(zend_jit_symtable_find);
414         REGISTER_HELPER(zend_jit_hash_index_lookup_rw);
415         REGISTER_HELPER(zend_jit_hash_lookup_rw);
416         REGISTER_HELPER(zend_jit_symtable_lookup_rw);
417         REGISTER_HELPER(zend_jit_symtable_lookup_w);
418         REGISTER_HELPER(zend_jit_undefined_op_helper);
419         REGISTER_HELPER(zend_jit_fetch_dim_r_helper);
420         REGISTER_HELPER(zend_jit_fetch_dim_is_helper);
421         REGISTER_HELPER(zend_jit_fetch_dim_isset_helper);
422         REGISTER_HELPER(zend_jit_fetch_dim_str_offset_r_helper);
423         REGISTER_HELPER(zend_jit_fetch_dim_str_r_helper);
424         REGISTER_HELPER(zend_jit_fetch_dim_str_is_helper);
425         REGISTER_HELPER(zend_jit_fetch_dim_obj_r_helper);
426         REGISTER_HELPER(zend_jit_fetch_dim_obj_is_helper);
427         REGISTER_HELPER(zend_jit_fetch_dim_rw_helper);
428         REGISTER_HELPER(zend_jit_fetch_dim_w_helper);
429         REGISTER_HELPER(zend_jit_fetch_dim_obj_rw_helper);
430         REGISTER_HELPER(zend_jit_fetch_dim_obj_w_helper);
431 //      REGISTER_HELPER(zend_jit_fetch_dim_obj_unset_helper);
432         REGISTER_HELPER(zend_jit_assign_dim_helper);
433         REGISTER_HELPER(zend_jit_assign_dim_op_helper);
434         REGISTER_HELPER(zend_jit_fast_assign_concat_helper);
435         REGISTER_HELPER(zend_jit_fast_concat_helper);
436         REGISTER_HELPER(zend_jit_isset_dim_helper);
437         REGISTER_HELPER(zend_jit_free_call_frame);
438         REGISTER_HELPER(zend_jit_fetch_global_helper);
439         REGISTER_HELPER(zend_jit_verify_arg_slow);
440         REGISTER_HELPER(zend_jit_verify_return_slow);
441         REGISTER_HELPER(zend_jit_fetch_obj_r_slow);
442         REGISTER_HELPER(zend_jit_fetch_obj_r_dynamic);
443         REGISTER_HELPER(zend_jit_fetch_obj_is_slow);
444         REGISTER_HELPER(zend_jit_fetch_obj_is_dynamic);
445         REGISTER_HELPER(zend_jit_fetch_obj_w_slow);
446         REGISTER_HELPER(zend_jit_check_array_promotion);
447         REGISTER_HELPER(zend_jit_create_typed_ref);
448         REGISTER_HELPER(zend_jit_extract_helper);
449         REGISTER_HELPER(zend_jit_vm_stack_free_args_helper);
450         REGISTER_HELPER(zend_jit_copy_extra_args_helper);
451         REGISTER_HELPER(zend_jit_deprecated_helper);
452         REGISTER_HELPER(zend_jit_assign_const_to_typed_ref);
453         REGISTER_HELPER(zend_jit_assign_tmp_to_typed_ref);
454         REGISTER_HELPER(zend_jit_assign_var_to_typed_ref);
455         REGISTER_HELPER(zend_jit_assign_cv_to_typed_ref);
456         REGISTER_HELPER(zend_jit_pre_inc_typed_ref);
457         REGISTER_HELPER(zend_jit_pre_dec_typed_ref);
458         REGISTER_HELPER(zend_jit_post_inc_typed_ref);
459         REGISTER_HELPER(zend_jit_post_dec_typed_ref);
460         REGISTER_HELPER(zend_jit_assign_op_to_typed_ref);
461         REGISTER_HELPER(zend_jit_only_vars_by_reference);
462         REGISTER_HELPER(zend_jit_invalid_array_access);
463         REGISTER_HELPER(zend_jit_invalid_property_read);
464         REGISTER_HELPER(zend_jit_invalid_property_write);
465         REGISTER_HELPER(zend_jit_invalid_property_incdec);
466         REGISTER_HELPER(zend_jit_invalid_property_assign);
467         REGISTER_HELPER(zend_jit_invalid_property_assign_op);
468         REGISTER_HELPER(zend_jit_prepare_assign_dim_ref);
469         REGISTER_HELPER(zend_jit_pre_inc);
470         REGISTER_HELPER(zend_jit_pre_dec);
471         REGISTER_HELPER(zend_runtime_jit);
472         REGISTER_HELPER(zend_jit_hot_func);
473         REGISTER_HELPER(zend_jit_check_constant);
474         REGISTER_HELPER(zend_jit_get_constant);
475         REGISTER_HELPER(zend_jit_array_free);
476         REGISTER_HELPER(zend_jit_zval_array_dup);
477         REGISTER_HELPER(zend_jit_add_arrays_helper);
478         REGISTER_HELPER(zend_jit_assign_obj_helper);
479         REGISTER_HELPER(zend_jit_assign_obj_op_helper);
480         REGISTER_HELPER(zend_jit_assign_to_typed_prop);
481         REGISTER_HELPER(zend_jit_assign_op_to_typed_prop);
482         REGISTER_HELPER(zend_jit_inc_typed_prop);
483         REGISTER_HELPER(zend_jit_dec_typed_prop);
484         REGISTER_HELPER(zend_jit_pre_inc_typed_prop);
485         REGISTER_HELPER(zend_jit_pre_dec_typed_prop);
486         REGISTER_HELPER(zend_jit_post_inc_typed_prop);
487         REGISTER_HELPER(zend_jit_post_dec_typed_prop);
488         REGISTER_HELPER(zend_jit_pre_inc_obj_helper);
489         REGISTER_HELPER(zend_jit_pre_dec_obj_helper);
490         REGISTER_HELPER(zend_jit_post_inc_obj_helper);
491         REGISTER_HELPER(zend_jit_post_dec_obj_helper);
492 #if (PHP_VERSION_ID <= 80100) && (SIZEOF_SIZE_T == 4)
493         REGISTER_HELPER(zval_jit_update_constant_ex);
494 #endif
495         REGISTER_HELPER(zend_jit_free_trampoline_helper);
496 #undef  REGISTER_HELPER
497
498 #ifndef _WIN32
499         zend_elf_load_symbols();
500 #endif
501
502         if (zend_vm_kind() == ZEND_VM_KIND_HYBRID) {
503                 zend_op opline;
504
505                 memset(&opline, 0, sizeof(opline));
506
507                 opline.opcode = ZEND_DO_UCALL;
508                 opline.result_type = IS_UNUSED;
509                 zend_vm_set_opcode_handler(&opline);
510                 zend_jit_disasm_add_symbol("ZEND_DO_UCALL_SPEC_RETVAL_UNUSED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
511
512                 opline.opcode = ZEND_DO_UCALL;
513                 opline.result_type = IS_VAR;
514                 zend_vm_set_opcode_handler(&opline);
515                 zend_jit_disasm_add_symbol("ZEND_DO_UCALL_SPEC_RETVAL_USED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
516
517                 opline.opcode = ZEND_DO_FCALL_BY_NAME;
518                 opline.result_type = IS_UNUSED;
519                 zend_vm_set_opcode_handler(&opline);
520                 zend_jit_disasm_add_symbol("ZEND_DO_FCALL_BY_NAME_SPEC_RETVAL_UNUSED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
521
522                 opline.opcode = ZEND_DO_FCALL_BY_NAME;
523                 opline.result_type = IS_VAR;
524                 zend_vm_set_opcode_handler(&opline);
525                 zend_jit_disasm_add_symbol("ZEND_DO_FCALL_BY_NAME_SPEC_RETVAL_USED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
526
527                 opline.opcode = ZEND_DO_FCALL;
528                 opline.result_type = IS_UNUSED;
529                 zend_vm_set_opcode_handler(&opline);
530                 zend_jit_disasm_add_symbol("ZEND_DO_FCALL_SPEC_RETVAL_UNUSED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
531
532                 opline.opcode = ZEND_DO_FCALL;
533                 opline.result_type = IS_VAR;
534                 zend_vm_set_opcode_handler(&opline);
535                 zend_jit_disasm_add_symbol("ZEND_DO_FCALL_SPEC_RETVAL_USED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
536
537                 opline.opcode = ZEND_RETURN;
538                 opline.op1_type = IS_CONST;
539                 zend_vm_set_opcode_handler(&opline);
540                 zend_jit_disasm_add_symbol("ZEND_RETURN_SPEC_CONST_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
541
542                 opline.opcode = ZEND_RETURN;
543                 opline.op1_type = IS_TMP_VAR;
544                 zend_vm_set_opcode_handler(&opline);
545                 zend_jit_disasm_add_symbol("ZEND_RETURN_SPEC_TMP_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
546
547                 opline.opcode = ZEND_RETURN;
548                 opline.op1_type = IS_VAR;
549                 zend_vm_set_opcode_handler(&opline);
550                 zend_jit_disasm_add_symbol("ZEND_RETURN_SPEC_VAR_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
551
552                 opline.opcode = ZEND_RETURN;
553                 opline.op1_type = IS_CV;
554                 zend_vm_set_opcode_handler(&opline);
555                 zend_jit_disasm_add_symbol("ZEND_RETURN_SPEC_CV_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
556
557                 zend_jit_disasm_add_symbol("ZEND_HYBRID_HALT_LABEL", (uint64_t)(uintptr_t)zend_jit_halt_op->handler, sizeof(void*));
558         }
559
560         return 1;
561 }
562
563 static void zend_jit_disasm_shutdown(void)
564 {
565         if (JIT_G(symbols)) {
566                 zend_jit_disasm_destroy_symbols(JIT_G(symbols));
567                 JIT_G(symbols) = NULL;
568         }
569 }