mirror of
https://github.com/php/php-src.git
synced 2024-12-17 13:59:28 +08:00
c19977d054
It's possible for delayed early binding opcodes to get optimized away if they are "unreachable". However, we still need to attempt early binding for them. (In some cases we also corrupt the early binding list outright during optimization, which is how I got here.) Fix this by storing information about delayed early binding independently of DECLARE_CLASS_DELAYED opcodes, so early binding is performed even after the opcode has been dropped.
95 lines
3.4 KiB
C
95 lines
3.4 KiB
C
/*
|
|
+----------------------------------------------------------------------+
|
|
| Zend OPcache |
|
|
+----------------------------------------------------------------------+
|
|
| Copyright (c) The PHP Group |
|
|
+----------------------------------------------------------------------+
|
|
| This source file is subject to version 3.01 of the PHP license, |
|
|
| that is bundled with this package in the file LICENSE, and is |
|
|
| available through the world-wide-web at the following url: |
|
|
| https://www.php.net/license/3_01.txt |
|
|
| If you did not receive a copy of the PHP license and are unable to |
|
|
| obtain it through the world-wide-web, please send a note to |
|
|
| license@php.net so we can mail you a copy immediately. |
|
|
+----------------------------------------------------------------------+
|
|
| Authors: Andi Gutmans <andi@php.net> |
|
|
| Zeev Suraski <zeev@php.net> |
|
|
| Stanislav Malyshev <stas@zend.com> |
|
|
| Dmitry Stogov <dmitry@php.net> |
|
|
+----------------------------------------------------------------------+
|
|
*/
|
|
|
|
/* pass 10:
|
|
* - remove NOPs
|
|
*/
|
|
|
|
#include "Optimizer/zend_optimizer.h"
|
|
#include "Optimizer/zend_optimizer_internal.h"
|
|
#include "zend_API.h"
|
|
#include "zend_constants.h"
|
|
#include "zend_execute.h"
|
|
#include "zend_vm.h"
|
|
|
|
void zend_optimizer_nop_removal(zend_op_array *op_array, zend_optimizer_ctx *ctx)
|
|
{
|
|
zend_op *end, *opline;
|
|
uint32_t new_count, i, shift;
|
|
int j;
|
|
uint32_t *shiftlist;
|
|
ALLOCA_FLAG(use_heap);
|
|
|
|
shiftlist = (uint32_t *)do_alloca(sizeof(uint32_t) * op_array->last, use_heap);
|
|
i = new_count = shift = 0;
|
|
end = op_array->opcodes + op_array->last;
|
|
for (opline = op_array->opcodes; opline < end; opline++) {
|
|
|
|
/* Kill JMP-over-NOP-s */
|
|
if (opline->opcode == ZEND_JMP && ZEND_OP1_JMP_ADDR(opline) > op_array->opcodes + i) {
|
|
/* check if there are only NOPs under the branch */
|
|
zend_op *target = ZEND_OP1_JMP_ADDR(opline) - 1;
|
|
|
|
while (target->opcode == ZEND_NOP) {
|
|
target--;
|
|
}
|
|
if (target == opline) {
|
|
/* only NOPs */
|
|
opline->opcode = ZEND_NOP;
|
|
}
|
|
}
|
|
|
|
shiftlist[i++] = shift;
|
|
if (opline->opcode == ZEND_NOP) {
|
|
shift++;
|
|
} else {
|
|
if (shift) {
|
|
zend_op *new_opline = op_array->opcodes + new_count;
|
|
|
|
*new_opline = *opline;
|
|
zend_optimizer_migrate_jump(op_array, new_opline, opline);
|
|
}
|
|
new_count++;
|
|
}
|
|
}
|
|
|
|
if (shift) {
|
|
op_array->last = new_count;
|
|
end = op_array->opcodes + op_array->last;
|
|
|
|
/* update JMPs */
|
|
for (opline = op_array->opcodes; opline<end; opline++) {
|
|
zend_optimizer_shift_jump(op_array, opline, shiftlist);
|
|
}
|
|
|
|
/* update try/catch array */
|
|
for (j = 0; j < op_array->last_try_catch; j++) {
|
|
op_array->try_catch_array[j].try_op -= shiftlist[op_array->try_catch_array[j].try_op];
|
|
op_array->try_catch_array[j].catch_op -= shiftlist[op_array->try_catch_array[j].catch_op];
|
|
if (op_array->try_catch_array[j].finally_op) {
|
|
op_array->try_catch_array[j].finally_op -= shiftlist[op_array->try_catch_array[j].finally_op];
|
|
op_array->try_catch_array[j].finally_end -= shiftlist[op_array->try_catch_array[j].finally_end];
|
|
}
|
|
}
|
|
}
|
|
free_alloca(shiftlist, use_heap);
|
|
}
|