mirror of
https://github.com/php/php-src.git
synced 2025-01-10 21:14:37 +08:00
Merge identical constants (and related cache_slots) in op_array->literals table.
This commit is contained in:
parent
36d343c0c4
commit
2bfb523f45
481
ext/opcache/Optimizer/compact_literals.c
Normal file
481
ext/opcache/Optimizer/compact_literals.c
Normal file
@ -0,0 +1,481 @@
|
||||
/* pass 11
|
||||
* - compact literals table
|
||||
*/
|
||||
#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
|
||||
|
||||
#define DEBUG_COMPACT_LITERALS 0
|
||||
|
||||
#define LITERAL_VALUE 0x0100
|
||||
#define LITERAL_FUNC 0x0200
|
||||
#define LITERAL_CLASS 0x0300
|
||||
#define LITERAL_CONST 0x0400
|
||||
#define LITERAL_CLASS_CONST 0x0500
|
||||
#define LITERAL_STATIC_METHOD 0x0600
|
||||
#define LITERAL_STATIC_PROPERTY 0x0700
|
||||
#define LITERAL_METHOD 0x0800
|
||||
#define LITERAL_PROPERTY 0x0900
|
||||
|
||||
#define LITERAL_EX_CLASS 0x4000
|
||||
#define LITERAL_EX_OBJ 0x2000
|
||||
#define LITERAL_MAY_MERGE 0x1000
|
||||
#define LITERAL_KIND_MASK 0x0f00
|
||||
#define LITERAL_NUM_RELATED_MASK 0x000f
|
||||
#define LITERAL_NUM_SLOTS_MASK 0x00f0
|
||||
#define LITERAL_NUM_SLOTS_SHIFT 4
|
||||
|
||||
#define LITERAL_NUM_RELATED(info) (info & LITERAL_NUM_RELATED_MASK)
|
||||
#define LITERAL_NUM_SLOTS(info) ((info & LITERAL_NUM_SLOTS_MASK) >> LITERAL_NUM_SLOTS_SHIFT)
|
||||
|
||||
typedef struct _literal_info {
|
||||
zend_uint flags; /* bitmask (see defines above) */
|
||||
union {
|
||||
int num; /* variable number or class name literal number */
|
||||
} u;
|
||||
} literal_info;
|
||||
|
||||
#define LITERAL_FLAGS(kind, slots, related) \
|
||||
((kind) | ((slots) << LITERAL_NUM_SLOTS_SHIFT) | (related))
|
||||
|
||||
#define LITERAL_INFO(n, kind, merge, slots, related) do { \
|
||||
info[n].flags = (((merge) ? LITERAL_MAY_MERGE : 0) | LITERAL_FLAGS(kind, slots, related)); \
|
||||
} while (0)
|
||||
|
||||
#define LITERAL_INFO_CLASS(n, kind, merge, slots, related, _num) do { \
|
||||
info[n].flags = (LITERAL_EX_CLASS | ((merge) ? LITERAL_MAY_MERGE : 0) | LITERAL_FLAGS(kind, slots, related)); \
|
||||
info[n].u.num = (_num); \
|
||||
} while (0)
|
||||
|
||||
#define LITERAL_INFO_OBJ(n, kind, merge, slots, related, _num) do { \
|
||||
info[n].flags = (LITERAL_EX_OBJ | ((merge) ? LITERAL_MAY_MERGE : 0) | LITERAL_FLAGS(kind, slots, related)); \
|
||||
info[n].u.num = (_num); \
|
||||
} while (0)
|
||||
|
||||
static void optimizer_literal_obj_info(literal_info *info,
|
||||
zend_uchar op_type,
|
||||
znode_op op,
|
||||
int constant,
|
||||
zend_uint kind,
|
||||
zend_uint slots,
|
||||
zend_uint related,
|
||||
zend_op_array *op_array)
|
||||
{
|
||||
/* For now we merge only $this object properties and methods.
|
||||
* In general it's also possible to do it for any CV variable as well,
|
||||
* but it would require complex dataflow and/or type analysis.
|
||||
*/
|
||||
if (Z_TYPE(op_array->literals[constant].constant) == IS_STRING &&
|
||||
op_type == IS_UNUSED) {
|
||||
LITERAL_INFO_OBJ(constant, kind, 1, slots, related, op_array->this_var);
|
||||
} else {
|
||||
LITERAL_INFO(constant, kind, 0, slots, related);
|
||||
}
|
||||
}
|
||||
|
||||
static void optimizer_literal_class_info(literal_info *info,
|
||||
zend_uchar op_type,
|
||||
znode_op op,
|
||||
int constant,
|
||||
zend_uint kind,
|
||||
zend_uint slots,
|
||||
zend_uint related,
|
||||
zend_op_array *op_array)
|
||||
{
|
||||
if (op_type == IS_CONST) {
|
||||
LITERAL_INFO_CLASS(constant, kind, 1, slots, related, op.constant);
|
||||
} else {
|
||||
LITERAL_INFO(constant, kind, 0, slots, related);
|
||||
}
|
||||
}
|
||||
|
||||
static void optimizer_compact_literals(zend_op_array *op_array TSRMLS_DC)
|
||||
{
|
||||
zend_op *opline, *end;
|
||||
int i, j, n, *pos, *map, cache_slots;
|
||||
ulong h;
|
||||
literal_info *info;
|
||||
int l_null = -1;
|
||||
int l_false = -1;
|
||||
int l_true = -1;
|
||||
HashTable hash;
|
||||
char *key;
|
||||
int key_len;
|
||||
|
||||
if (op_array->last_literal) {
|
||||
info = (literal_info*)ecalloc(op_array->last_literal, sizeof(literal_info));
|
||||
|
||||
/* Mark literals of specific types */
|
||||
opline = op_array->opcodes;
|
||||
end = opline + op_array->last;
|
||||
while (opline < end) {
|
||||
switch (opline->opcode) {
|
||||
case ZEND_DO_FCALL:
|
||||
LITERAL_INFO(opline->op1.constant, LITERAL_FUNC, 1, 1, 1);
|
||||
break;
|
||||
case ZEND_INIT_FCALL_BY_NAME:
|
||||
if (ZEND_OP2_TYPE(opline) == IS_CONST) {
|
||||
LITERAL_INFO(opline->op2.constant, LITERAL_FUNC, 1, 1, 2);
|
||||
}
|
||||
break;
|
||||
case ZEND_INIT_NS_FCALL_BY_NAME:
|
||||
LITERAL_INFO(opline->op2.constant, LITERAL_FUNC, 1, 1, 3);
|
||||
break;
|
||||
case ZEND_INIT_METHOD_CALL:
|
||||
if (ZEND_OP2_TYPE(opline) == IS_CONST) {
|
||||
optimizer_literal_obj_info(
|
||||
info,
|
||||
opline->op1_type,
|
||||
opline->op1,
|
||||
opline->op2.constant,
|
||||
LITERAL_METHOD, 2, 2,
|
||||
op_array);
|
||||
}
|
||||
break;
|
||||
case ZEND_INIT_STATIC_METHOD_CALL:
|
||||
if (ZEND_OP1_TYPE(opline) == IS_CONST) {
|
||||
LITERAL_INFO(opline->op1.constant, LITERAL_CLASS, 1, 1, 2);
|
||||
}
|
||||
if (ZEND_OP2_TYPE(opline) == IS_CONST) {
|
||||
optimizer_literal_class_info(
|
||||
info,
|
||||
opline->op1_type,
|
||||
opline->op1,
|
||||
opline->op2.constant,
|
||||
LITERAL_STATIC_METHOD, (ZEND_OP1_TYPE(opline) == IS_CONST) ? 1 : 2, 2,
|
||||
op_array);
|
||||
}
|
||||
break;
|
||||
case ZEND_CATCH:
|
||||
LITERAL_INFO(opline->op1.constant, LITERAL_CLASS, 1, 1, 2);
|
||||
break;
|
||||
case ZEND_FETCH_CONSTANT:
|
||||
if (ZEND_OP1_TYPE(opline) == IS_UNUSED) {
|
||||
if ((opline->extended_value & (IS_CONSTANT_IN_NAMESPACE|IS_CONSTANT_UNQUALIFIED)) == (IS_CONSTANT_IN_NAMESPACE|IS_CONSTANT_UNQUALIFIED)) {
|
||||
LITERAL_INFO(opline->op2.constant, LITERAL_CONST, 1, 1, 5);
|
||||
} else {
|
||||
LITERAL_INFO(opline->op2.constant, LITERAL_CONST, 1, 1, 3);
|
||||
}
|
||||
} else {
|
||||
if (ZEND_OP1_TYPE(opline) == IS_CONST) {
|
||||
LITERAL_INFO(opline->op1.constant, LITERAL_CLASS, 1, 1, 2);
|
||||
}
|
||||
optimizer_literal_class_info(
|
||||
info,
|
||||
opline->op1_type,
|
||||
opline->op1,
|
||||
opline->op2.constant,
|
||||
LITERAL_CLASS_CONST, (ZEND_OP1_TYPE(opline) == IS_CONST) ? 1 : 2, 1,
|
||||
op_array);
|
||||
}
|
||||
break;
|
||||
case ZEND_FETCH_R:
|
||||
case ZEND_FETCH_W:
|
||||
case ZEND_FETCH_RW:
|
||||
case ZEND_FETCH_IS:
|
||||
case ZEND_FETCH_UNSET:
|
||||
case ZEND_FETCH_FUNC_ARG:
|
||||
case ZEND_UNSET_VAR:
|
||||
case ZEND_ISSET_ISEMPTY_VAR:
|
||||
if (ZEND_OP2_TYPE(opline) == IS_UNUSED) {
|
||||
if (ZEND_OP1_TYPE(opline) == IS_CONST) {
|
||||
LITERAL_INFO(opline->op1.constant, LITERAL_VALUE, 1, 0, 1);
|
||||
}
|
||||
} else {
|
||||
if (ZEND_OP2_TYPE(opline) == IS_CONST) {
|
||||
LITERAL_INFO(opline->op2.constant, LITERAL_CLASS, 1, 1, 2);
|
||||
}
|
||||
if (ZEND_OP1_TYPE(opline) == IS_CONST) {
|
||||
optimizer_literal_class_info(
|
||||
info,
|
||||
opline->op2_type,
|
||||
opline->op2,
|
||||
opline->op1.constant,
|
||||
LITERAL_STATIC_PROPERTY, 2, 1,
|
||||
op_array);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ZEND_FETCH_CLASS:
|
||||
case ZEND_ADD_INTERFACE:
|
||||
case ZEND_ADD_TRAIT:
|
||||
if (ZEND_OP2_TYPE(opline) == IS_CONST) {
|
||||
LITERAL_INFO(opline->op2.constant, LITERAL_CLASS, 1, 1, 2);
|
||||
}
|
||||
break;
|
||||
case ZEND_ASSIGN_OBJ:
|
||||
case ZEND_FETCH_OBJ_R:
|
||||
case ZEND_FETCH_OBJ_W:
|
||||
case ZEND_FETCH_OBJ_RW:
|
||||
case ZEND_FETCH_OBJ_IS:
|
||||
case ZEND_FETCH_OBJ_UNSET:
|
||||
case ZEND_FETCH_OBJ_FUNC_ARG:
|
||||
case ZEND_UNSET_OBJ:
|
||||
case ZEND_PRE_INC_OBJ:
|
||||
case ZEND_PRE_DEC_OBJ:
|
||||
case ZEND_POST_INC_OBJ:
|
||||
case ZEND_POST_DEC_OBJ:
|
||||
case ZEND_ISSET_ISEMPTY_PROP_OBJ:
|
||||
if (ZEND_OP2_TYPE(opline) == IS_CONST) {
|
||||
optimizer_literal_obj_info(
|
||||
info,
|
||||
opline->op1_type,
|
||||
opline->op1,
|
||||
opline->op2.constant,
|
||||
LITERAL_PROPERTY, 2, 1,
|
||||
op_array);
|
||||
}
|
||||
break;
|
||||
case ZEND_ASSIGN_ADD:
|
||||
case ZEND_ASSIGN_SUB:
|
||||
case ZEND_ASSIGN_MUL:
|
||||
case ZEND_ASSIGN_DIV:
|
||||
case ZEND_ASSIGN_MOD:
|
||||
case ZEND_ASSIGN_SL:
|
||||
case ZEND_ASSIGN_SR:
|
||||
case ZEND_ASSIGN_CONCAT:
|
||||
case ZEND_ASSIGN_BW_OR:
|
||||
case ZEND_ASSIGN_BW_AND:
|
||||
case ZEND_ASSIGN_BW_XOR:
|
||||
if (ZEND_OP2_TYPE(opline) == IS_CONST) {
|
||||
if (opline->extended_value == ZEND_ASSIGN_OBJ) {
|
||||
optimizer_literal_obj_info(
|
||||
info,
|
||||
opline->op1_type,
|
||||
opline->op1,
|
||||
opline->op2.constant,
|
||||
LITERAL_PROPERTY, 2, 1,
|
||||
op_array);
|
||||
} else {
|
||||
LITERAL_INFO(opline->op2.constant, LITERAL_VALUE, 1, 0, 1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (ZEND_OP1_TYPE(opline) == IS_CONST) {
|
||||
LITERAL_INFO(opline->op1.constant, LITERAL_VALUE, 1, 0, 1);
|
||||
}
|
||||
if (ZEND_OP2_TYPE(opline) == IS_CONST) {
|
||||
LITERAL_INFO(opline->op2.constant, LITERAL_VALUE, 1, 0, 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
opline++;
|
||||
}
|
||||
|
||||
#if DEBUG_COMPACT_LITERALS
|
||||
{
|
||||
int i, use_copy;
|
||||
fprintf(stderr, "File %s func %s\n", op_array->filename,
|
||||
op_array->function_name? op_array->function_name : "main");
|
||||
fprintf(stderr, "Literlas table size %d\n", op_array->last_literal);
|
||||
|
||||
for (i = 0; i < op_array->last_literal; i++) {
|
||||
zval zv = op_array->literals[i].constant;
|
||||
zend_make_printable_zval(&op_array->literals[i].constant, &zv, &use_copy);
|
||||
fprintf(stderr, "Literal %d, val (%d):%s\n", i, Z_STRLEN(zv), Z_STRVAL(zv));
|
||||
if (use_copy) {
|
||||
zval_dtor(&zv);
|
||||
}
|
||||
}
|
||||
fflush(stderr);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Merge equal constants */
|
||||
j = 0; cache_slots = 0;
|
||||
zend_hash_init(&hash, 16, NULL, NULL, 0);
|
||||
map = (int*)ecalloc(op_array->last_literal, sizeof(int));
|
||||
for (i = 0; i < op_array->last_literal; i++) {
|
||||
if (!info[i].flags) {
|
||||
/* unsed literal */
|
||||
zval_dtor(&op_array->literals[i].constant);
|
||||
continue;
|
||||
}
|
||||
switch (Z_TYPE(op_array->literals[i].constant)) {
|
||||
case IS_NULL:
|
||||
if (l_null < 0) {
|
||||
l_null = j;
|
||||
if (i != j) {
|
||||
op_array->literals[j] = op_array->literals[i];
|
||||
info[j] = info[i];
|
||||
}
|
||||
j++;
|
||||
}
|
||||
map[i] = l_null;
|
||||
break;
|
||||
case IS_BOOL:
|
||||
if (Z_LVAL(op_array->literals[i].constant)) {
|
||||
if (l_true < 0) {
|
||||
l_true = j;
|
||||
if (i != j) {
|
||||
op_array->literals[j] = op_array->literals[i];
|
||||
info[j] = info[i];
|
||||
}
|
||||
j++;
|
||||
}
|
||||
map[i] = l_true;
|
||||
} else {
|
||||
if (l_false < 0) {
|
||||
l_false = j;
|
||||
if (i != j) {
|
||||
op_array->literals[j] = op_array->literals[i];
|
||||
info[j] = info[i];
|
||||
}
|
||||
j++;
|
||||
}
|
||||
map[i] = l_false;
|
||||
}
|
||||
break;
|
||||
case IS_LONG:
|
||||
if (zend_hash_index_find(&hash, Z_LVAL(op_array->literals[i].constant), (void**)&pos) == SUCCESS) {
|
||||
map[i] = *pos;
|
||||
} else {
|
||||
map[i] = j;
|
||||
zend_hash_index_update(&hash, Z_LVAL(op_array->literals[i].constant), (void**)&j, sizeof(int), NULL);
|
||||
if (i != j) {
|
||||
op_array->literals[j] = op_array->literals[i];
|
||||
info[j] = info[i];
|
||||
}
|
||||
j++;
|
||||
}
|
||||
break;
|
||||
case IS_DOUBLE:
|
||||
if (zend_hash_find(&hash, (char*)&Z_DVAL(op_array->literals[i].constant), sizeof(double), (void**)&pos) == SUCCESS) {
|
||||
map[i] = *pos;
|
||||
} else {
|
||||
map[i] = j;
|
||||
zend_hash_add(&hash, (char*)&Z_DVAL(op_array->literals[i].constant), sizeof(double), (void**)&j, sizeof(int), NULL);
|
||||
if (i != j) {
|
||||
op_array->literals[j] = op_array->literals[i];
|
||||
info[j] = info[i];
|
||||
}
|
||||
j++;
|
||||
}
|
||||
break;
|
||||
case IS_STRING:
|
||||
case IS_CONSTANT:
|
||||
if (info[i].flags & LITERAL_MAY_MERGE) {
|
||||
if (info[i].flags & LITERAL_EX_OBJ) {
|
||||
key_len = MAX_LENGTH_OF_LONG + sizeof("->") + Z_STRLEN(op_array->literals[i].constant);
|
||||
key = emalloc(key_len);
|
||||
key_len = snprintf(key, key_len-1, "%d->%s", info[i].u.num, Z_STRVAL(op_array->literals[i].constant));
|
||||
} else if (info[i].flags & LITERAL_EX_CLASS) {
|
||||
zval *class_name = &op_array->literals[(info[i].u.num < i) ? map[info[i].u.num] : info[i].u.num].constant;
|
||||
key_len = Z_STRLEN_P(class_name) + sizeof("::") + Z_STRLEN(op_array->literals[i].constant);
|
||||
key = emalloc(key_len);
|
||||
memcpy(key, Z_STRVAL_P(class_name), Z_STRLEN_P(class_name));
|
||||
memcpy(key + Z_STRLEN_P(class_name), "::", sizeof("::") - 1);
|
||||
memcpy(key + Z_STRLEN_P(class_name) + sizeof("::") - 1,
|
||||
Z_STRVAL(op_array->literals[i].constant),
|
||||
Z_STRLEN(op_array->literals[i].constant) + 1);
|
||||
} else {
|
||||
key = Z_STRVAL(op_array->literals[i].constant);
|
||||
key_len = Z_STRLEN(op_array->literals[i].constant)+1;
|
||||
}
|
||||
h = zend_hash_func(key, key_len);
|
||||
h += info[i].flags;
|
||||
}
|
||||
if ((info[i].flags & LITERAL_MAY_MERGE) &&
|
||||
zend_hash_quick_find(&hash, key, key_len, h, (void**)&pos) == SUCCESS &&
|
||||
Z_TYPE(op_array->literals[i].constant) == Z_TYPE(op_array->literals[*pos].constant) &&
|
||||
info[i].flags == info[*pos].flags) {
|
||||
|
||||
if (info[i].flags & (LITERAL_EX_OBJ|LITERAL_EX_CLASS)) {
|
||||
efree(key);
|
||||
}
|
||||
map[i] = *pos;
|
||||
zval_dtor(&op_array->literals[i].constant);
|
||||
n = LITERAL_NUM_RELATED(info[i].flags);
|
||||
while (n > 1) {
|
||||
i++;
|
||||
zval_dtor(&op_array->literals[i].constant);
|
||||
n--;
|
||||
}
|
||||
} else {
|
||||
map[i] = j;
|
||||
if (info[i].flags & LITERAL_MAY_MERGE) {
|
||||
zend_hash_quick_add(&hash, key, key_len, h, (void**)&j, sizeof(int), NULL);
|
||||
if (info[i].flags & (LITERAL_EX_OBJ|LITERAL_EX_CLASS)) {
|
||||
efree(key);
|
||||
}
|
||||
}
|
||||
if (i != j) {
|
||||
op_array->literals[j] = op_array->literals[i];
|
||||
info[j] = info[i];
|
||||
}
|
||||
if (!op_array->literals[j].hash_value) {
|
||||
if (IS_INTERNED(Z_STRVAL(op_array->literals[j].constant))) {
|
||||
op_array->literals[j].hash_value = INTERNED_HASH(Z_STRVAL(op_array->literals[j].constant));
|
||||
} else {
|
||||
op_array->literals[j].hash_value = zend_hash_func(Z_STRVAL(op_array->literals[j].constant), Z_STRLEN(op_array->literals[j].constant)+1);
|
||||
}
|
||||
}
|
||||
if (LITERAL_NUM_SLOTS(info[i].flags)) {
|
||||
op_array->literals[j].cache_slot = cache_slots;
|
||||
cache_slots += LITERAL_NUM_SLOTS(info[i].flags);
|
||||
}
|
||||
j++;
|
||||
n = LITERAL_NUM_RELATED(info[i].flags);
|
||||
while (n > 1) {
|
||||
i++;
|
||||
if (i != j) op_array->literals[j] = op_array->literals[i];
|
||||
if (!op_array->literals[j].hash_value) {
|
||||
if (IS_INTERNED(Z_STRVAL(op_array->literals[j].constant))) {
|
||||
op_array->literals[j].hash_value = INTERNED_HASH(Z_STRVAL(op_array->literals[j].constant));
|
||||
} else {
|
||||
op_array->literals[j].hash_value = zend_hash_func(Z_STRVAL(op_array->literals[j].constant), Z_STRLEN(op_array->literals[j].constant)+1);
|
||||
}
|
||||
}
|
||||
j++;
|
||||
n--;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* don't merge other types */
|
||||
map[i] = j;
|
||||
if (i != j) {
|
||||
op_array->literals[j] = op_array->literals[i];
|
||||
info[j] = info[i];
|
||||
}
|
||||
j++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
zend_hash_destroy(&hash);
|
||||
op_array->last_literal = j;
|
||||
op_array->last_cache_slot = cache_slots;
|
||||
|
||||
/* Update opcodes to use new literals table */
|
||||
opline = op_array->opcodes;
|
||||
end = opline + op_array->last;
|
||||
while (opline < end) {
|
||||
if (ZEND_OP1_TYPE(opline) == IS_CONST) {
|
||||
opline->op1.constant = map[opline->op1.constant];
|
||||
}
|
||||
if (ZEND_OP2_TYPE(opline) == IS_CONST) {
|
||||
opline->op2.constant = map[opline->op2.constant];
|
||||
}
|
||||
opline++;
|
||||
}
|
||||
efree(map);
|
||||
efree(info);
|
||||
|
||||
#if DEBUG_COMPACT_LITERALS
|
||||
{
|
||||
int i, use_copy;
|
||||
fprintf(stderr, "Optimized literlas table size %d\n", op_array->last_literal);
|
||||
|
||||
for (i = 0; i < op_array->last_literal; i++) {
|
||||
zval zv = op_array->literals[i].constant;
|
||||
zend_make_printable_zval(&op_array->literals[i].constant, &zv, &use_copy);
|
||||
fprintf(stderr, "Literal %d, val (%d):%s\n", i, Z_STRLEN(zv), Z_STRVAL(zv));
|
||||
if (use_copy) {
|
||||
zval_dtor(&zv);
|
||||
}
|
||||
}
|
||||
fflush(stderr);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
@ -112,6 +112,7 @@ int zend_optimizer_add_literal(zend_op_array *op_array, const zval *zv TSRMLS_DC
|
||||
#include "Optimizer/nop_removal.c"
|
||||
#include "Optimizer/block_pass.c"
|
||||
#include "Optimizer/optimize_temp_vars_5.c"
|
||||
#include "Optimizer/compact_literals.c"
|
||||
|
||||
static void zend_optimize(zend_op_array *op_array,
|
||||
zend_persistent_script *script,
|
||||
@ -150,7 +151,7 @@ static void zend_optimize(zend_op_array *op_array,
|
||||
*/
|
||||
#include "Optimizer/pass5.c"
|
||||
|
||||
/* pass 9:
|
||||
/* pass 9:
|
||||
* - Optimize temp variables usage
|
||||
*/
|
||||
#include "Optimizer/pass9.c"
|
||||
@ -159,6 +160,15 @@ static void zend_optimize(zend_op_array *op_array,
|
||||
* - remove NOPs
|
||||
*/
|
||||
#include "Optimizer/pass10.c"
|
||||
|
||||
#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
|
||||
/* pass 11:
|
||||
* - Compact literals table
|
||||
*/
|
||||
if (ZEND_OPTIMIZER_PASS_11 & OPTIMIZATION_LEVEL) {
|
||||
optimizer_compact_literals(op_array TSRMLS_CC);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void zend_accel_optimize(zend_op_array *op_array,
|
||||
|
@ -35,7 +35,7 @@
|
||||
#define ZEND_OPTIMIZER_PASS_8 (1<<7)
|
||||
#define ZEND_OPTIMIZER_PASS_9 (1<<8) /* TMP VAR usage */
|
||||
#define ZEND_OPTIMIZER_PASS_10 (1<<9) /* NOP removal */
|
||||
#define ZEND_OPTIMIZER_PASS_11 (1<<10)
|
||||
#define ZEND_OPTIMIZER_PASS_11 (1<<10) /* Merge equal constants */
|
||||
#define ZEND_OPTIMIZER_PASS_12 (1<<11)
|
||||
#define ZEND_OPTIMIZER_PASS_13 (1<<12)
|
||||
#define ZEND_OPTIMIZER_PASS_14 (1<<13)
|
||||
|
215
ext/opcache/tests/compact_literals.phpt
Normal file
215
ext/opcache/tests/compact_literals.phpt
Normal file
@ -0,0 +1,215 @@
|
||||
--TEST--
|
||||
Test with compact literals
|
||||
--INI--
|
||||
opcache.enable=1
|
||||
opcache.enable_cli=1
|
||||
opcache.optimization_level=-1
|
||||
--SKIPIF--
|
||||
<?php require_once('skipif.inc'); ?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
echo "array key hash" . ":" . PHP_EOL;
|
||||
$array = array(
|
||||
"1" => "one",
|
||||
"2" => "two",
|
||||
"one" => 1,
|
||||
"two" => 2,
|
||||
);
|
||||
|
||||
unset($array["one"]);
|
||||
unset($array["2"]);
|
||||
|
||||
print_r($array);
|
||||
|
||||
echo "funcion define" . ":" . PHP_EOL;
|
||||
if (!function_exists("dummy")) {
|
||||
function dummy() {
|
||||
var_dump(__FUNCTION__);
|
||||
}
|
||||
}
|
||||
|
||||
dummy();
|
||||
|
||||
$dummy = function () { var_dump("lambda" . "dummy"); };
|
||||
$dummy();
|
||||
|
||||
if (!class_exists("A")) {
|
||||
class A {
|
||||
public static $name = "A";
|
||||
public static function say($n = "name") {
|
||||
var_dump(static::$name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class B extends A {
|
||||
public static $name = "B";
|
||||
}
|
||||
|
||||
if (!class_exists("C")) {
|
||||
class C extends B {
|
||||
public static $name = "C";
|
||||
}
|
||||
}
|
||||
|
||||
A::say();
|
||||
B::Say();
|
||||
A::say();
|
||||
B::say();
|
||||
C::say();
|
||||
|
||||
function get_eol_define() {
|
||||
define("MY_EOL", PHP_EOL);
|
||||
}
|
||||
get_eol_define();
|
||||
define("EOL", MY_EOL);
|
||||
|
||||
echo "constants define" . ":" . EOL;
|
||||
|
||||
echo "define " . "TEST" . EOL;
|
||||
define("TEST", "TEST");
|
||||
|
||||
class E {
|
||||
public static $E="EP";
|
||||
const E="E";
|
||||
const TEST="NULL";
|
||||
}
|
||||
|
||||
class F {
|
||||
const F="F";
|
||||
public static $E="FEP";
|
||||
const E="FE";
|
||||
const TEST="FALSE";
|
||||
public static $F = "FP";
|
||||
}
|
||||
|
||||
var_dump(TEST); //"TEST"
|
||||
var_dump(E::E); //"E"
|
||||
var_dump(F::E); //"FE"
|
||||
var_dump(F::F); //"F"
|
||||
var_dump(E::TEST); //"NULL"
|
||||
var_dump(F::TEST); //"FALSE"
|
||||
var_dump(E::$E); //"EP"
|
||||
var_dumP(F::$F); //"FP"
|
||||
var_dumP(F::$E); //"FEP"
|
||||
|
||||
echo "propertes and methods" . EOL;
|
||||
|
||||
class CH {
|
||||
const H = "H";
|
||||
public function h() {
|
||||
var_dump(self::H);
|
||||
}
|
||||
}
|
||||
|
||||
class CI {
|
||||
const H = "I";
|
||||
public function h() {
|
||||
var_dump(self::H);
|
||||
}
|
||||
}
|
||||
|
||||
function change(&$obj) {
|
||||
$obj = new CH;
|
||||
}
|
||||
|
||||
function geti() {
|
||||
return new CI;
|
||||
}
|
||||
|
||||
$h = new CH;
|
||||
|
||||
echo "-->H" . PHP_EOL;
|
||||
$h->H();
|
||||
var_dump($h::H);
|
||||
var_dump(CH::H);
|
||||
|
||||
$h->H();
|
||||
var_dump($h::H);
|
||||
var_dump(CH::H);
|
||||
|
||||
echo "-->I" . PHP_EOL;
|
||||
$h = new CI;
|
||||
$h->H();
|
||||
var_dump($h::H);
|
||||
var_dump(CI::H);
|
||||
$h->H();
|
||||
var_dump($h::H);
|
||||
var_dump(CI::H);
|
||||
|
||||
echo "-->H" . PHP_EOL;
|
||||
change($h);
|
||||
|
||||
$h->H();
|
||||
var_dump($h::H);
|
||||
var_dump(CH::H);
|
||||
|
||||
$h->H();
|
||||
var_dump($h::H);
|
||||
var_dump(CH::H);
|
||||
|
||||
echo "-->I" . PHP_EOL;
|
||||
$h = geti();
|
||||
$h->H();
|
||||
var_dump($h::H);
|
||||
var_dump(CI::H);
|
||||
$h->H();
|
||||
var_dump($h::H);
|
||||
var_dump(CI::H);
|
||||
?>
|
||||
--EXPECT--
|
||||
array key hash:
|
||||
Array
|
||||
(
|
||||
[1] => one
|
||||
[two] => 2
|
||||
)
|
||||
funcion define:
|
||||
string(5) "dummy"
|
||||
string(11) "lambdadummy"
|
||||
string(1) "A"
|
||||
string(1) "B"
|
||||
string(1) "A"
|
||||
string(1) "B"
|
||||
string(1) "C"
|
||||
constants define:
|
||||
define TEST
|
||||
string(4) "TEST"
|
||||
string(1) "E"
|
||||
string(2) "FE"
|
||||
string(1) "F"
|
||||
string(4) "NULL"
|
||||
string(5) "FALSE"
|
||||
string(2) "EP"
|
||||
string(2) "FP"
|
||||
string(3) "FEP"
|
||||
propertes and methods
|
||||
-->H
|
||||
string(1) "H"
|
||||
string(1) "H"
|
||||
string(1) "H"
|
||||
string(1) "H"
|
||||
string(1) "H"
|
||||
string(1) "H"
|
||||
-->I
|
||||
string(1) "I"
|
||||
string(1) "I"
|
||||
string(1) "I"
|
||||
string(1) "I"
|
||||
string(1) "I"
|
||||
string(1) "I"
|
||||
-->H
|
||||
string(1) "H"
|
||||
string(1) "H"
|
||||
string(1) "H"
|
||||
string(1) "H"
|
||||
string(1) "H"
|
||||
string(1) "H"
|
||||
-->I
|
||||
string(1) "I"
|
||||
string(1) "I"
|
||||
string(1) "I"
|
||||
string(1) "I"
|
||||
string(1) "I"
|
||||
string(1) "I"
|
Loading…
Reference in New Issue
Block a user