Coverage Report

Created: 2026-09-14 06:25

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