Coverage Report

Created: 2025-07-23 06:33

/src/php-src/Zend/Optimizer/escape_analysis.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
   +----------------------------------------------------------------------+
3
   | Zend OPcache, Escape Analysis                                        |
4
   +----------------------------------------------------------------------+
5
   | Copyright (c) The PHP Group                                          |
6
   +----------------------------------------------------------------------+
7
   | This source file is subject to version 3.01 of the PHP license,      |
8
   | that is bundled with this package in the file LICENSE, and is        |
9
   | available through the world-wide-web at the following url:           |
10
   | https://www.php.net/license/3_01.txt                                 |
11
   | If you did not receive a copy of the PHP license and are unable to   |
12
   | obtain it through the world-wide-web, please send a note to          |
13
   | license@php.net so we can mail you a copy immediately.               |
14
   +----------------------------------------------------------------------+
15
   | Authors: Dmitry Stogov <dmitry@php.net>                              |
16
   +----------------------------------------------------------------------+
17
*/
18
19
#include "Optimizer/zend_optimizer.h"
20
#include "Optimizer/zend_optimizer_internal.h"
21
#include "zend_bitset.h"
22
#include "zend_cfg.h"
23
#include "zend_ssa.h"
24
#include "zend_inference.h"
25
#include "zend_dump.h"
26
27
/*
28
 * T. Kotzmann and H. Mossenbock. Escape analysis  in the context of dynamic
29
 * compilation and deoptimization. In Proceedings of the International
30
 * Conference on Virtual Execution Environments, pages 111-120, Chicago,
31
 * June 2005
32
 */
33
34
static zend_always_inline void union_find_init(int *parent, int *size, int count) /* {{{ */
35
10.4k
{
36
10.4k
  int i;
37
38
451k
  for (i = 0; i < count; i++) {
39
441k
    parent[i] = i;
40
441k
    size[i] = 1;
41
441k
  }
42
10.4k
}
43
/* }}} */
44
45
static zend_always_inline int union_find_root(int *parent, int i) /* {{{ */
46
879k
{
47
879k
  int p = parent[i];
48
49
1.21M
  while (i != p) {
50
331k
    p = parent[p];
51
331k
    parent[i] = p;
52
331k
    i = p;
53
331k
    p = parent[i];
54
331k
  }
55
879k
  return i;
56
879k
}
57
/* }}} */
58
59
static zend_always_inline void union_find_unite(int *parent, int *size, int i, int j) /* {{{ */
60
218k
{
61
218k
  int r1 = union_find_root(parent, i);
62
218k
  int r2 = union_find_root(parent, j);
63
64
218k
  if (r1 != r2) {
65
164k
    if (size[r1] < size[r2]) {
66
80.5k
      parent[r1] = r2;
67
80.5k
      size[r2] += size[r1];
68
83.6k
    } else {
69
83.6k
      parent[r2] = r1;
70
83.6k
      size[r1] += size[r2];
71
83.6k
    }
72
164k
  }
73
218k
}
74
/* }}} */
75
76
static zend_result zend_build_equi_escape_sets(int *parent, zend_op_array *op_array, zend_ssa *ssa) /* {{{ */
77
10.4k
{
78
10.4k
  zend_ssa_var *ssa_vars = ssa->vars;
79
10.4k
  int ssa_vars_count = ssa->vars_count;
80
10.4k
  zend_ssa_phi *p;
81
10.4k
  int i, j;
82
10.4k
  int *size;
83
10.4k
  ALLOCA_FLAG(use_heap)
84
85
10.4k
  size = do_alloca(sizeof(int) * ssa_vars_count, use_heap);
86
10.4k
  if (!size) {
87
0
    return FAILURE;
88
0
  }
89
10.4k
  union_find_init(parent, size, ssa_vars_count);
90
91
451k
  for (i = 0; i < ssa_vars_count; i++) {
92
441k
    if (ssa_vars[i].definition_phi) {
93
70.1k
      p = ssa_vars[i].definition_phi;
94
70.1k
      if (p->pi >= 0) {
95
20.5k
        union_find_unite(parent, size, i, p->sources[0]);
96
49.5k
      } else {
97
151k
        for (j = 0; j < ssa->cfg.blocks[p->block].predecessors_count; j++) {
98
101k
          union_find_unite(parent, size, i, p->sources[j]);
99
101k
        }
100
49.5k
      }
101
371k
    } else if (ssa_vars[i].definition >= 0) {
102
340k
      int def = ssa_vars[i].definition;
103
340k
      zend_ssa_op *op = ssa->ops + def;
104
340k
      zend_op *opline =  op_array->opcodes + def;
105
106
340k
      if (op->op1_def >= 0) {
107
64.1k
        if (op->op1_use >= 0) {
108
64.1k
          if (opline->opcode != ZEND_ASSIGN) {
109
31.8k
            union_find_unite(parent, size, op->op1_def, op->op1_use);
110
31.8k
          }
111
64.1k
        }
112
64.1k
        if (opline->opcode == ZEND_ASSIGN && op->op2_use >= 0) {
113
22.5k
          union_find_unite(parent, size, op->op1_def, op->op2_use);
114
22.5k
        }
115
64.1k
      }
116
340k
      if (op->op2_def >= 0) {
117
4.37k
        if (op->op2_use >= 0) {
118
4.17k
          union_find_unite(parent, size, op->op2_def, op->op2_use);
119
4.17k
        }
120
4.37k
      }
121
340k
      if (op->result_def >= 0) {
122
298k
        if (op->result_use >= 0) {
123
19.4k
          if (opline->opcode != ZEND_QM_ASSIGN) {
124
19.4k
            union_find_unite(parent, size, op->result_def, op->result_use);
125
19.4k
          }
126
19.4k
        }
127
298k
        if (opline->opcode == ZEND_QM_ASSIGN && op->op1_use >= 0) {
128
1.19k
          union_find_unite(parent, size, op->result_def, op->op1_use);
129
1.19k
        }
130
298k
        if (opline->opcode == ZEND_ASSIGN && op->op2_use >= 0) {
131
7.92k
          union_find_unite(parent, size, op->result_def, op->op2_use);
132
7.92k
        }
133
298k
        if (opline->opcode == ZEND_ASSIGN && op->op1_def >= 0) {
134
9.17k
          union_find_unite(parent, size, op->result_def, op->op1_def);
135
9.17k
        }
136
298k
      }
137
340k
    }
138
441k
  }
139
140
451k
  for (i = 0; i < ssa_vars_count; i++) {
141
441k
    parent[i] = union_find_root(parent, i);
142
441k
  }
143
144
10.4k
  free_alloca(size, use_heap);
145
146
10.4k
  return SUCCESS;
147
10.4k
}
148
/* }}} */
149
150
static bool is_allocation_def(zend_op_array *op_array, zend_ssa *ssa, int def, int var, const zend_script *script) /* {{{ */
151
338k
{
152
338k
  zend_ssa_op *ssa_op = ssa->ops + def;
153
338k
  zend_op *opline = op_array->opcodes + def;
154
155
338k
  if (ssa_op->result_def == var) {
156
267k
    switch (opline->opcode) {
157
6.09k
      case ZEND_INIT_ARRAY:
158
6.09k
        return 1;
159
29.1k
      case ZEND_NEW: {
160
          /* objects with destructors should escape */
161
29.1k
        zend_class_entry *ce = zend_optimizer_get_class_entry_from_op1(
162
29.1k
          script, op_array, opline);
163
29.1k
        uint32_t forbidden_flags =
164
          /* These flags will always cause an exception */
165
29.1k
          ZEND_ACC_IMPLICIT_ABSTRACT_CLASS | ZEND_ACC_EXPLICIT_ABSTRACT_CLASS
166
29.1k
          | ZEND_ACC_INTERFACE | ZEND_ACC_TRAIT;
167
29.1k
        if (ce
168
29.1k
         && !ce->parent
169
29.1k
         && !ce->create_object
170
29.1k
         && ce->default_object_handlers->get_constructor == zend_std_get_constructor
171
29.1k
         && ce->default_object_handlers->dtor_obj == zend_objects_destroy_object
172
29.1k
         && !ce->constructor
173
29.1k
         && !ce->destructor
174
29.1k
         && !ce->__get
175
29.1k
         && !ce->__set
176
29.1k
         && !(ce->ce_flags & forbidden_flags)
177
29.1k
         && (ce->ce_flags & ZEND_ACC_CONSTANTS_UPDATED)) {
178
10.2k
          return 1;
179
10.2k
        }
180
18.9k
        break;
181
29.1k
      }
182
18.9k
      case ZEND_QM_ASSIGN:
183
2.29k
        if (opline->op1_type == IS_CONST
184
2.29k
         && Z_TYPE_P(CRT_CONSTANT(opline->op1)) == IS_ARRAY) {
185
86
          return 1;
186
86
        }
187
2.20k
        if (opline->op1_type == IS_CV && (OP1_INFO() & MAY_BE_ARRAY)) {
188
180
          return 1;
189
180
        }
190
2.02k
        break;
191
2.02k
      case ZEND_ASSIGN:
192
726
        if (opline->op1_type == IS_CV && (OP1_INFO() & MAY_BE_ARRAY)) {
193
232
          return 1;
194
232
        }
195
494
        break;
196
267k
    }
197
267k
  } else if (ssa_op->op1_def == var) {
198
69.3k
    switch (opline->opcode) {
199
38.6k
      case ZEND_ASSIGN:
200
38.6k
        if (opline->op2_type == IS_CONST
201
38.6k
         && Z_TYPE_P(CRT_CONSTANT(opline->op2)) == IS_ARRAY) {
202
6.22k
          return 1;
203
6.22k
        }
204
32.4k
        if (opline->op2_type == IS_CV && (OP2_INFO() & MAY_BE_ARRAY)) {
205
469
          return 1;
206
469
        }
207
31.9k
        break;
208
31.9k
      case ZEND_ASSIGN_DIM:
209
2.10k
        if (OP1_INFO() & (MAY_BE_UNDEF | MAY_BE_NULL | MAY_BE_FALSE)) {
210
          /* implicit object/array allocation */
211
2.01k
          return 1;
212
2.01k
        }
213
88
        break;
214
69.3k
    }
215
69.3k
  }
216
217
312k
  return 0;
218
338k
}
219
/* }}} */
220
221
static bool is_local_def(zend_op_array *op_array, zend_ssa *ssa, int def, int var, const zend_script *script) /* {{{ */
222
125k
{
223
125k
  zend_ssa_op *op = ssa->ops + def;
224
125k
  zend_op *opline = op_array->opcodes + def;
225
226
125k
  if (op->result_def == var) {
227
97.9k
    switch (opline->opcode) {
228
4.04k
      case ZEND_INIT_ARRAY:
229
23.0k
      case ZEND_ADD_ARRAY_ELEMENT:
230
23.3k
      case ZEND_QM_ASSIGN:
231
23.6k
      case ZEND_ASSIGN:
232
23.6k
        return 1;
233
9.50k
      case ZEND_NEW: {
234
        /* objects with destructors should escape */
235
9.50k
        zend_class_entry *ce = zend_optimizer_get_class_entry_from_op1(
236
9.50k
          script, op_array, opline);
237
9.50k
        if (ce
238
9.50k
         && !ce->create_object
239
9.50k
         && ce->default_object_handlers->get_constructor == zend_std_get_constructor
240
9.50k
         && ce->default_object_handlers->dtor_obj == zend_objects_destroy_object
241
9.50k
         && !ce->constructor
242
9.50k
         && !ce->destructor
243
9.50k
         && !ce->__get
244
9.50k
         && !ce->__set
245
9.50k
         && !ce->parent) {
246
6.23k
          return 1;
247
6.23k
        }
248
3.26k
        break;
249
9.50k
      }
250
97.9k
    }
251
97.9k
  } else if (op->op1_def == var) {
252
25.3k
    switch (opline->opcode) {
253
13.1k
      case ZEND_ASSIGN:
254
16.8k
      case ZEND_ASSIGN_DIM:
255
18.5k
      case ZEND_ASSIGN_OBJ:
256
18.5k
      case ZEND_ASSIGN_OBJ_REF:
257
18.6k
      case ZEND_ASSIGN_DIM_OP:
258
18.7k
      case ZEND_ASSIGN_OBJ_OP:
259
18.8k
      case ZEND_PRE_INC_OBJ:
260
18.9k
      case ZEND_PRE_DEC_OBJ:
261
18.9k
      case ZEND_POST_INC_OBJ:
262
18.9k
      case ZEND_POST_DEC_OBJ:
263
18.9k
        return 1;
264
25.3k
    }
265
25.3k
  }
266
267
76.2k
  return 0;
268
125k
}
269
/* }}} */
270
271
static bool is_escape_use(zend_op_array *op_array, zend_ssa *ssa, int use, int var) /* {{{ */
272
25.0k
{
273
25.0k
  zend_ssa_op *ssa_op = ssa->ops + use;
274
25.0k
  zend_op *opline = op_array->opcodes + use;
275
276
25.0k
  if (ssa_op->op1_use == var) {
277
13.3k
    switch (opline->opcode) {
278
663
      case ZEND_ASSIGN:
279
        /* no_val */
280
663
        break;
281
144
      case ZEND_QM_ASSIGN:
282
144
        if (opline->op1_type == IS_CV) {
283
144
          if (OP1_INFO() & MAY_BE_OBJECT) {
284
            /* object aliasing */
285
130
            return 1;
286
130
          }
287
144
        }
288
14
        break;
289
55
      case ZEND_ISSET_ISEMPTY_DIM_OBJ:
290
75
      case ZEND_ISSET_ISEMPTY_PROP_OBJ:
291
1.73k
      case ZEND_FETCH_DIM_R:
292
1.92k
      case ZEND_FETCH_OBJ_R:
293
2.28k
      case ZEND_FETCH_DIM_IS:
294
2.29k
      case ZEND_FETCH_OBJ_IS:
295
2.29k
        break;
296
0
      case ZEND_ASSIGN_OP:
297
0
        return 1;
298
74
      case ZEND_ASSIGN_DIM_OP:
299
186
      case ZEND_ASSIGN_OBJ_OP:
300
186
      case ZEND_ASSIGN_STATIC_PROP_OP:
301
3.39k
      case ZEND_ASSIGN_DIM:
302
3.88k
      case ZEND_ASSIGN_OBJ:
303
3.91k
      case ZEND_ASSIGN_OBJ_REF:
304
3.91k
        break;
305
0
      case ZEND_PRE_INC_OBJ:
306
8
      case ZEND_PRE_DEC_OBJ:
307
8
      case ZEND_POST_INC_OBJ:
308
8
      case ZEND_POST_DEC_OBJ:
309
8
        break;
310
465
      case ZEND_INIT_ARRAY:
311
1.15k
      case ZEND_ADD_ARRAY_ELEMENT:
312
1.15k
        if (opline->extended_value & ZEND_ARRAY_ELEMENT_REF) {
313
0
          return 1;
314
0
        }
315
1.15k
        if (OP1_INFO() & MAY_BE_OBJECT) {
316
          /* object aliasing */
317
599
          return 1;
318
599
        }
319
        /* reference dependencies processed separately */
320
554
        break;
321
842
      case ZEND_OP_DATA:
322
842
        if ((opline-1)->opcode != ZEND_ASSIGN_DIM
323
842
         && (opline-1)->opcode != ZEND_ASSIGN_OBJ) {
324
74
          return 1;
325
74
        }
326
768
        if (OP1_INFO() & MAY_BE_OBJECT) {
327
          /* object aliasing */
328
614
          return 1;
329
614
        }
330
154
        opline--;
331
154
        ssa_op--;
332
154
        if (opline->op1_type != IS_CV
333
154
         || (OP1_INFO() & MAY_BE_REF)
334
154
         || (ssa_op->op1_def >= 0 && ssa->vars[ssa_op->op1_def].alias)) {
335
          /* assignment into escaping structure */
336
100
          return 1;
337
100
        }
338
        /* reference dependencies processed separately */
339
54
        break;
340
4.34k
      default:
341
4.34k
        return 1;
342
13.3k
    }
343
13.3k
  }
344
345
19.1k
  if (ssa_op->op2_use == var) {
346
4.29k
    switch (opline->opcode) {
347
3.81k
      case ZEND_ASSIGN:
348
3.81k
        if (opline->op1_type != IS_CV
349
3.81k
         || (OP1_INFO() & MAY_BE_REF)
350
3.81k
         || (ssa_op->op1_def >= 0 && ssa->vars[ssa_op->op1_def].alias)) {
351
          /* assignment into escaping variable */
352
2.84k
          return 1;
353
2.84k
        }
354
970
        if (opline->op2_type == IS_CV || opline->result_type != IS_UNUSED) {
355
141
          if (OP2_INFO() & MAY_BE_OBJECT) {
356
            /* object aliasing */
357
79
            return 1;
358
79
          }
359
141
        }
360
891
        break;
361
891
      default:
362
486
        return 1;
363
4.29k
    }
364
4.29k
  }
365
366
15.7k
  if (ssa_op->result_use == var) {
367
7.36k
    switch (opline->opcode) {
368
0
      case ZEND_ASSIGN:
369
0
      case ZEND_QM_ASSIGN:
370
0
      case ZEND_INIT_ARRAY:
371
7.36k
      case ZEND_ADD_ARRAY_ELEMENT:
372
7.36k
        break;
373
0
      default:
374
0
        return 1;
375
7.36k
    }
376
7.36k
  }
377
378
15.7k
  return 0;
379
15.7k
}
380
/* }}} */
381
382
zend_result zend_ssa_escape_analysis(const zend_script *script, zend_op_array *op_array, zend_ssa *ssa) /* {{{ */
383
78.5k
{
384
78.5k
  zend_ssa_var *ssa_vars = ssa->vars;
385
78.5k
  int ssa_vars_count = ssa->vars_count;
386
78.5k
  int i, root, use;
387
78.5k
  int *ees;
388
78.5k
  bool has_allocations;
389
78.5k
  int num_non_escaped;
390
78.5k
  ALLOCA_FLAG(use_heap)
391
392
78.5k
  if (!ssa_vars) {
393
0
    return SUCCESS;
394
0
  }
395
396
78.5k
  has_allocations = 0;
397
1.03M
  for (i = op_array->last_var; i < ssa_vars_count; i++) {
398
966k
    if (ssa_vars[i].definition >= 0
399
966k
      && (ssa->var_info[i].type & (MAY_BE_ARRAY|MAY_BE_OBJECT))
400
966k
      && is_allocation_def(op_array, ssa, ssa_vars[i].definition, i, script)) {
401
10.4k
      has_allocations = 1;
402
10.4k
      break;
403
10.4k
    }
404
966k
  }
405
78.5k
  if (!has_allocations) {
406
68.1k
    return SUCCESS;
407
68.1k
  }
408
409
410
  /* 1. Build EES (Equi-Escape Sets) */
411
10.4k
  ees = do_alloca(sizeof(int) * ssa_vars_count, use_heap);
412
10.4k
  if (!ees) {
413
0
    return FAILURE;
414
0
  }
415
416
10.4k
  if (zend_build_equi_escape_sets(ees, op_array, ssa) == FAILURE) {
417
0
    free_alloca(ees, use_heap);
418
0
    return FAILURE;
419
0
  }
420
421
  /* 2. Identify Allocations */
422
10.4k
  num_non_escaped = 0;
423
420k
  for (i = op_array->last_var; i < ssa_vars_count; i++) {
424
410k
    root = ees[i];
425
410k
    if (ssa_vars[root].escape_state > ESCAPE_STATE_NO_ESCAPE) {
426
      /* already escape. skip */
427
366k
    } else if (ssa_vars[i].alias && (ssa->var_info[i].type & MAY_BE_REF)) {
428
0
      if (ssa_vars[root].escape_state == ESCAPE_STATE_NO_ESCAPE) {
429
0
        num_non_escaped--;
430
0
      }
431
0
      ssa_vars[root].escape_state = ESCAPE_STATE_GLOBAL_ESCAPE;
432
366k
    } else if (ssa_vars[i].definition >= 0
433
366k
       && (ssa->var_info[i].type & (MAY_BE_ARRAY|MAY_BE_OBJECT))) {
434
125k
      if (!is_local_def(op_array, ssa, ssa_vars[i].definition, i, script)) {
435
76.2k
        if (ssa_vars[root].escape_state == ESCAPE_STATE_NO_ESCAPE) {
436
3.31k
          num_non_escaped--;
437
3.31k
        }
438
76.2k
        ssa_vars[root].escape_state = ESCAPE_STATE_GLOBAL_ESCAPE;
439
76.2k
      } else if (ssa_vars[root].escape_state == ESCAPE_STATE_UNKNOWN
440
48.9k
       && is_allocation_def(op_array, ssa, ssa_vars[i].definition, i, script)) {
441
15.0k
        ssa_vars[root].escape_state = ESCAPE_STATE_NO_ESCAPE;
442
15.0k
        num_non_escaped++;
443
15.0k
      }
444
125k
    }
445
410k
  }
446
447
  /* 3. Mark escaped EES */
448
10.4k
  if (num_non_escaped) {
449
269k
    for (i = 0; i < ssa_vars_count; i++) {
450
261k
      if (ssa_vars[i].use_chain >= 0) {
451
216k
        root = ees[i];
452
216k
        if (ssa_vars[root].escape_state == ESCAPE_STATE_NO_ESCAPE) {
453
47.9k
          FOREACH_USE(ssa_vars + i, use) {
454
47.9k
            if (is_escape_use(op_array, ssa, use, i)) {
455
9.27k
              ssa_vars[root].escape_state = ESCAPE_STATE_GLOBAL_ESCAPE;
456
9.27k
              num_non_escaped--;
457
9.27k
              if (num_non_escaped == 0) {
458
5.90k
                i = ssa_vars_count;
459
5.90k
              }
460
9.27k
              break;
461
9.27k
            }
462
47.9k
          } FOREACH_USE_END();
463
22.9k
        }
464
216k
      }
465
261k
    }
466
7.54k
  }
467
468
  /* 4. Process referential dependencies */
469
10.4k
  if (num_non_escaped) {
470
1.63k
    bool changed;
471
472
1.67k
    do {
473
1.67k
      changed = 0;
474
87.1k
      for (i = 0; i < ssa_vars_count; i++) {
475
85.5k
        if (ssa_vars[i].use_chain >= 0) {
476
69.1k
          root = ees[i];
477
69.1k
          if (ssa_vars[root].escape_state == ESCAPE_STATE_NO_ESCAPE) {
478
16.5k
            FOREACH_USE(ssa_vars + i, use) {
479
16.5k
              zend_ssa_op *op = ssa->ops + use;
480
16.5k
              zend_op *opline = op_array->opcodes + use;
481
16.5k
              int enclosing_root;
482
483
16.5k
              if (opline->opcode == ZEND_OP_DATA &&
484
9.13k
                  ((opline-1)->opcode == ZEND_ASSIGN_DIM ||
485
46
                   (opline-1)->opcode == ZEND_ASSIGN_OBJ ||
486
46
                   (opline-1)->opcode == ZEND_ASSIGN_OBJ_REF) &&
487
9.13k
                  op->op1_use == i &&
488
9.13k
                  (op-1)->op1_use >= 0) {
489
46
                enclosing_root = ees[(op-1)->op1_use];
490
9.08k
              } else if ((opline->opcode == ZEND_INIT_ARRAY ||
491
9.08k
                   opline->opcode == ZEND_ADD_ARRAY_ELEMENT) &&
492
9.08k
                  op->op1_use == i &&
493
9.08k
                  op->result_def >= 0) {
494
1.07k
                enclosing_root = ees[op->result_def];
495
8.01k
              } else {
496
8.01k
                continue;
497
8.01k
              }
498
499
1.12k
              if (ssa_vars[enclosing_root].escape_state == ESCAPE_STATE_UNKNOWN ||
500
1.12k
                  ssa_vars[enclosing_root].escape_state > ssa_vars[root].escape_state) {
501
544
                  if (ssa_vars[enclosing_root].escape_state == ESCAPE_STATE_UNKNOWN) {
502
0
                  ssa_vars[root].escape_state = ESCAPE_STATE_GLOBAL_ESCAPE;
503
544
                  } else {
504
544
                  ssa_vars[root].escape_state = ssa_vars[enclosing_root].escape_state;
505
544
                }
506
544
                if (ssa_vars[root].escape_state == ESCAPE_STATE_GLOBAL_ESCAPE) {
507
544
                  num_non_escaped--;
508
544
                  if (num_non_escaped == 0) {
509
138
                    changed = 0;
510
406
                  } else {
511
406
                    changed = 1;
512
406
                  }
513
544
                  break;
514
544
                } else {
515
0
                  changed = 1;
516
0
                }
517
544
              }
518
1.12k
            } FOREACH_USE_END();
519
7.45k
          }
520
69.1k
        }
521
85.5k
      }
522
1.67k
    } while (changed);
523
1.63k
  }
524
525
  /* 5. Propagate values of escape sets to variables */
526
451k
  for (i = 0; i < ssa_vars_count; i++) {
527
441k
    root = ees[i];
528
441k
    if (i != root) {
529
164k
      ssa_vars[i].escape_state = ssa_vars[root].escape_state;
530
164k
    }
531
441k
  }
532
533
10.4k
  free_alloca(ees, use_heap);
534
535
10.4k
  return SUCCESS;
536
10.4k
}
537
/* }}} */