Coverage Report

Created: 2025-09-27 06:26

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