Coverage Report

Created: 2026-04-01 06:49

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