/src/php-src/Zend/Optimizer/nop_removal.c
Line | Count | Source |
1 | | /* |
2 | | +----------------------------------------------------------------------+ |
3 | | | Zend OPcache | |
4 | | +----------------------------------------------------------------------+ |
5 | | | Copyright © The PHP Group and Contributors. | |
6 | | +----------------------------------------------------------------------+ |
7 | | | This source file is subject to the Modified BSD License that is | |
8 | | | bundled with this package in the file LICENSE, and is available | |
9 | | | through the World Wide Web at <https://www.php.net/license/>. | |
10 | | | | |
11 | | | SPDX-License-Identifier: BSD-3-Clause | |
12 | | +----------------------------------------------------------------------+ |
13 | | | Authors: Andi Gutmans <andi@php.net> | |
14 | | | Zeev Suraski <zeev@php.net> | |
15 | | | Stanislav Malyshev <stas@zend.com> | |
16 | | | Dmitry Stogov <dmitry@php.net> | |
17 | | +----------------------------------------------------------------------+ |
18 | | */ |
19 | | |
20 | | /* pass 10: |
21 | | * - remove NOPs |
22 | | */ |
23 | | |
24 | | #include "Optimizer/zend_optimizer.h" |
25 | | #include "Optimizer/zend_optimizer_internal.h" |
26 | | #include "zend_API.h" |
27 | | #include "zend_constants.h" |
28 | | #include "zend_execute.h" |
29 | | #include "zend_vm.h" |
30 | | |
31 | | void zend_optimizer_nop_removal(zend_op_array *op_array, zend_optimizer_ctx *ctx) |
32 | 0 | { |
33 | 0 | zend_op *opline; |
34 | 0 | uint32_t new_count, i, shift; |
35 | 0 | uint32_t *shiftlist; |
36 | 0 | ALLOCA_FLAG(use_heap); |
37 | |
|
38 | 0 | shiftlist = (uint32_t *)do_alloca(sizeof(uint32_t) * op_array->last, use_heap); |
39 | 0 | i = new_count = shift = 0; |
40 | 0 | const zend_op *end = op_array->opcodes + op_array->last; |
41 | 0 | for (opline = op_array->opcodes; opline < end; opline++) { |
42 | | |
43 | | /* Kill JMP-over-NOP-s */ |
44 | 0 | if (opline->opcode == ZEND_JMP && ZEND_OP1_JMP_ADDR(opline) > op_array->opcodes + i) { |
45 | | /* check if there are only NOPs under the branch */ |
46 | 0 | const zend_op *target = ZEND_OP1_JMP_ADDR(opline) - 1; |
47 | |
|
48 | 0 | while (target->opcode == ZEND_NOP) { |
49 | 0 | target--; |
50 | 0 | } |
51 | 0 | if (target == opline) { |
52 | | /* only NOPs */ |
53 | 0 | opline->opcode = ZEND_NOP; |
54 | 0 | } |
55 | 0 | } |
56 | |
|
57 | 0 | shiftlist[i++] = shift; |
58 | 0 | if (opline->opcode == ZEND_NOP) { |
59 | 0 | shift++; |
60 | 0 | } else { |
61 | 0 | if (shift) { |
62 | 0 | zend_op *new_opline = op_array->opcodes + new_count; |
63 | |
|
64 | 0 | *new_opline = *opline; |
65 | 0 | zend_optimizer_migrate_jump(op_array, new_opline, opline); |
66 | 0 | } |
67 | 0 | new_count++; |
68 | 0 | } |
69 | 0 | } |
70 | |
|
71 | 0 | if (shift) { |
72 | 0 | op_array->last = new_count; |
73 | 0 | end = op_array->opcodes + op_array->last; |
74 | | |
75 | | /* update JMPs */ |
76 | 0 | for (opline = op_array->opcodes; opline<end; opline++) { |
77 | 0 | zend_optimizer_shift_jump(op_array, opline, shiftlist); |
78 | 0 | } |
79 | | |
80 | | /* update try/catch array */ |
81 | 0 | for (uint32_t j = 0; j < op_array->last_try_catch; j++) { |
82 | 0 | op_array->try_catch_array[j].try_op -= shiftlist[op_array->try_catch_array[j].try_op]; |
83 | 0 | op_array->try_catch_array[j].catch_op -= shiftlist[op_array->try_catch_array[j].catch_op]; |
84 | 0 | if (op_array->try_catch_array[j].finally_op) { |
85 | 0 | op_array->try_catch_array[j].finally_op -= shiftlist[op_array->try_catch_array[j].finally_op]; |
86 | 0 | op_array->try_catch_array[j].finally_end -= shiftlist[op_array->try_catch_array[j].finally_end]; |
87 | 0 | } |
88 | 0 | } |
89 | 0 | } |
90 | | free_alloca(shiftlist, use_heap); |
91 | 0 | } |