Coverage Report

Created: 2025-12-14 06:09

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