summaryrefslogtreecommitdiff
path: root/ext
diff options
context:
space:
mode:
authorDmitry Stogov <dmitry@zend.com>2018-02-05 19:41:47 +0300
committerDmitry Stogov <dmitry@zend.com>2018-02-05 19:41:47 +0300
commitca035f26aa296acf553f289e2d459fd052367db2 (patch)
treedcf38faa85759c7c076f3a11371a422ca7f5bee2 /ext
parent070a0091b39b1196fe66bf2ba3c52ad4533f5497 (diff)
downloadphp-git-ca035f26aa296acf553f289e2d459fd052367db2.tar.gz
Moved "zval.u2.cache_slot" into free room of "zend_op"
Diffstat (limited to 'ext')
-rw-r--r--ext/opcache/Optimizer/block_pass.c2
-rw-r--r--ext/opcache/Optimizer/compact_literals.c565
-rw-r--r--ext/opcache/Optimizer/dfa_pass.c2
-rw-r--r--ext/opcache/Optimizer/optimize_func_calls.c2
-rw-r--r--ext/opcache/Optimizer/sccp.c4
-rw-r--r--ext/opcache/Optimizer/zend_cfg.c4
-rw-r--r--ext/opcache/Optimizer/zend_dump.c2
-rw-r--r--ext/opcache/Optimizer/zend_optimizer.c117
-rw-r--r--ext/opcache/zend_file_cache.c4
-rw-r--r--ext/opcache/zend_persist.c2
10 files changed, 491 insertions, 213 deletions
diff --git a/ext/opcache/Optimizer/block_pass.c b/ext/opcache/Optimizer/block_pass.c
index 65007a9455..9c0fd96471 100644
--- a/ext/opcache/Optimizer/block_pass.c
+++ b/ext/opcache/Optimizer/block_pass.c
@@ -965,7 +965,7 @@ static void assemble_code_blocks(zend_cfg *cfg, zend_op_array *op_array, zend_op
ZEND_SET_OP_JMP_ADDR(opline, opline->op2, new_opcodes + blocks[b->successors[0]].start);
break;
case ZEND_CATCH:
- if (opline->extended_value != ZEND_LAST_CATCH) {
+ if (!(opline->extended_value & ZEND_LAST_CATCH)) {
ZEND_SET_OP_JMP_ADDR(opline, opline->op2, new_opcodes + blocks[b->successors[0]].start);
}
break;
diff --git a/ext/opcache/Optimizer/compact_literals.c b/ext/opcache/Optimizer/compact_literals.c
index 63102beaac..b74df321f1 100644
--- a/ext/opcache/Optimizer/compact_literals.c
+++ b/ext/opcache/Optimizer/compact_literals.c
@@ -42,76 +42,77 @@
#define LITERAL_PROPERTY 0x0900
#define LITERAL_GLOBAL 0x0A00
-#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 {
uint32_t 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); \
+#define LITERAL_INFO(n, kind, related) do { \
+ info[n].flags = ((kind) | (related)); \
} while (0)
-#define LITERAL_INFO_OBJ(n, kind, merge, slots, related) do { \
- info[n].flags = (LITERAL_EX_OBJ | ((merge) ? LITERAL_MAY_MERGE : 0) | LITERAL_FLAGS(kind, slots, related)); \
- info[n].u.num = (uint32_t)-1; \
- } while (0)
-
-static void optimizer_literal_obj_info(literal_info *info,
- zend_uchar op_type,
- znode_op op,
- int constant,
- uint32_t kind,
- uint32_t slots,
- uint32_t related,
- zend_op_array *op_array)
+static zend_bool class_name_type_hint(const zend_op_array *op_array, uint32_t arg_num)
{
- /* 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]) == IS_STRING &&
- op_type == IS_UNUSED) {
- LITERAL_INFO_OBJ(constant, kind, 1, slots, related);
+ zend_arg_info *arg_info;
+
+ if (arg_num > 0) {
+ if (op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) {
+ if (EXPECTED(arg_num <= op_array->num_args)) {
+ arg_info = &op_array->arg_info[arg_num-1];
+ } else if (UNEXPECTED(op_array->fn_flags & ZEND_ACC_VARIADIC)) {
+ arg_info = &op_array->arg_info[op_array->num_args];
+ } else {
+ return 0;
+ }
+ return ZEND_TYPE_IS_CLASS(arg_info->type);
+ }
} else {
- LITERAL_INFO(constant, kind, 0, slots, related);
+ arg_info = op_array->arg_info - 1;
+ return ZEND_TYPE_IS_CLASS(arg_info->type);
}
+ return 0;
}
-static void optimizer_literal_class_info(literal_info *info,
- zend_uchar op_type,
- znode_op op,
- int constant,
- uint32_t kind,
- uint32_t slots,
- uint32_t related,
- zend_op_array *op_array)
+static uint32_t add_static_slot(HashTable *hash,
+ zend_op_array *op_array,
+ uint32_t op1,
+ uint32_t op2,
+ uint32_t kind,
+ int *cache_size)
{
- if (op_type == IS_CONST) {
- LITERAL_INFO_CLASS(constant, kind, 1, slots, related, op.constant);
+ uint32_t ret;
+ zend_string *key;
+ size_t key_len;
+ zval *class_name = &op_array->literals[op1];
+ zval *prop_name = &op_array->literals[op2];
+ zval *pos, tmp;
+
+ key_len = Z_STRLEN_P(class_name) + sizeof("::") - 1 + Z_STRLEN_P(prop_name);
+ key = zend_string_alloc(key_len, 0);
+ memcpy(ZSTR_VAL(key), Z_STRVAL_P(class_name), Z_STRLEN_P(class_name));
+ memcpy(ZSTR_VAL(key) + Z_STRLEN_P(class_name), "::", sizeof("::") - 1);
+ memcpy(ZSTR_VAL(key) + Z_STRLEN_P(class_name) + sizeof("::") - 1,
+ Z_STRVAL_P(prop_name),
+ Z_STRLEN_P(prop_name) + 1);
+
+ ZSTR_H(key) = zend_hash_func(ZSTR_VAL(key), ZSTR_LEN(key));
+ ZSTR_H(key) += kind;
+
+ pos = zend_hash_find(hash, key);
+ if (pos) {
+ ret = Z_LVAL_P(pos);
} else {
- LITERAL_INFO(constant, kind, 0, slots, related);
+ ret = *cache_size;
+ *cache_size += 2 * sizeof(void *);
+ ZVAL_LONG(&tmp, ret);
+ zend_hash_add(hash, key, &tmp);
}
+ zend_string_release(key);
+ return ret;
}
void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx *ctx)
@@ -127,9 +128,9 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
HashTable hash;
zend_string *key = NULL;
void *checkpoint = zend_arena_checkpoint(ctx->arena);
+ int *const_slot, *class_slot, *func_slot, *bind_var_slot, *property_slot, *method_slot;
if (op_array->last_literal) {
- cache_size = 0;
info = (literal_info*)zend_arena_calloc(&ctx->arena, op_array->last_literal, sizeof(literal_info));
/* Mark literals of specific types */
@@ -138,66 +139,48 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
while (opline < end) {
switch (opline->opcode) {
case ZEND_INIT_FCALL:
- LITERAL_INFO(opline->op2.constant, LITERAL_FUNC, 1, 1, 1);
+ LITERAL_INFO(opline->op2.constant, LITERAL_FUNC, 1);
break;
case ZEND_INIT_FCALL_BY_NAME:
- LITERAL_INFO(opline->op2.constant, LITERAL_FUNC, 1, 1, 2);
+ LITERAL_INFO(opline->op2.constant, LITERAL_FUNC, 2);
break;
case ZEND_INIT_NS_FCALL_BY_NAME:
- LITERAL_INFO(opline->op2.constant, LITERAL_FUNC, 1, 1, 3);
+ LITERAL_INFO(opline->op2.constant, LITERAL_FUNC, 3);
break;
case ZEND_INIT_METHOD_CALL:
if (opline->op1_type == IS_CONST) {
- LITERAL_INFO(opline->op1.constant, LITERAL_VALUE, 1, 0, 1);
+ LITERAL_INFO(opline->op1.constant, LITERAL_VALUE, 1);
}
if (opline->op2_type == IS_CONST) {
- optimizer_literal_obj_info(
- info,
- opline->op1_type,
- opline->op1,
- opline->op2.constant,
- LITERAL_METHOD, 2, 2,
- op_array);
+ LITERAL_INFO(opline->op2.constant, LITERAL_METHOD, 2);
}
break;
case ZEND_INIT_STATIC_METHOD_CALL:
if (opline->op1_type == IS_CONST) {
- LITERAL_INFO(opline->op1.constant, LITERAL_CLASS, 1, 1, 2);
+ LITERAL_INFO(opline->op1.constant, LITERAL_CLASS, 2);
}
if (opline->op2_type == IS_CONST) {
- optimizer_literal_class_info(
- info,
- opline->op1_type,
- opline->op1,
- opline->op2.constant,
- LITERAL_STATIC_METHOD, (opline->op1_type == IS_CONST) ? 1 : 2, 2,
- op_array);
+ LITERAL_INFO(opline->op2.constant, LITERAL_STATIC_METHOD, 2);
}
break;
case ZEND_CATCH:
- LITERAL_INFO(opline->op1.constant, LITERAL_CLASS, 1, 1, 2);
+ LITERAL_INFO(opline->op1.constant, LITERAL_CLASS, 2);
break;
case ZEND_DEFINED:
- LITERAL_INFO(opline->op1.constant, LITERAL_CONST, 1, 1, 2);
+ LITERAL_INFO(opline->op1.constant, LITERAL_CONST, 2);
break;
case ZEND_FETCH_CONSTANT:
if ((opline->op1.num & (IS_CONSTANT_IN_NAMESPACE|IS_CONSTANT_UNQUALIFIED)) == (IS_CONSTANT_IN_NAMESPACE|IS_CONSTANT_UNQUALIFIED)) {
- LITERAL_INFO(opline->op2.constant, LITERAL_CONST, 1, 1, 5);
+ LITERAL_INFO(opline->op2.constant, LITERAL_CONST, 5);
} else {
- LITERAL_INFO(opline->op2.constant, LITERAL_CONST, 1, 1, 3);
+ LITERAL_INFO(opline->op2.constant, LITERAL_CONST, 3);
}
break;
case ZEND_FETCH_CLASS_CONSTANT:
if (opline->op1_type == IS_CONST) {
- LITERAL_INFO(opline->op1.constant, LITERAL_CLASS, 1, 1, 2);
+ LITERAL_INFO(opline->op1.constant, LITERAL_CLASS, 2);
}
- optimizer_literal_class_info(
- info,
- opline->op1_type,
- opline->op1,
- opline->op2.constant,
- LITERAL_CLASS_CONST, (opline->op1_type == IS_CONST) ? 1 : 2, 1,
- op_array);
+ LITERAL_INFO(opline->op2.constant, LITERAL_CLASS_CONST, 1);
break;
case ZEND_FETCH_STATIC_PROP_R:
case ZEND_FETCH_STATIC_PROP_W:
@@ -208,16 +191,10 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
case ZEND_UNSET_STATIC_PROP:
case ZEND_ISSET_ISEMPTY_STATIC_PROP:
if (opline->op2_type == IS_CONST) {
- LITERAL_INFO(opline->op2.constant, LITERAL_CLASS, 1, 1, 2);
+ LITERAL_INFO(opline->op2.constant, LITERAL_CLASS, 2);
}
if (opline->op1_type == IS_CONST) {
- optimizer_literal_class_info(
- info,
- opline->op2_type,
- opline->op2,
- opline->op1.constant,
- LITERAL_STATIC_PROPERTY, 2, 1,
- op_array);
+ LITERAL_INFO(opline->op1.constant, LITERAL_STATIC_PROPERTY, 1);
}
break;
case ZEND_FETCH_CLASS:
@@ -225,12 +202,12 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
case ZEND_ADD_TRAIT:
case ZEND_INSTANCEOF:
if (opline->op2_type == IS_CONST) {
- LITERAL_INFO(opline->op2.constant, LITERAL_CLASS, 1, 1, 2);
+ LITERAL_INFO(opline->op2.constant, LITERAL_CLASS, 2);
}
break;
case ZEND_NEW:
if (opline->op1_type == IS_CONST) {
- LITERAL_INFO(opline->op1.constant, LITERAL_CLASS, 1, 1, 2);
+ LITERAL_INFO(opline->op1.constant, LITERAL_CLASS, 2);
}
break;
case ZEND_ASSIGN_OBJ:
@@ -247,13 +224,7 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
case ZEND_POST_DEC_OBJ:
case ZEND_ISSET_ISEMPTY_PROP_OBJ:
if (opline->op2_type == IS_CONST) {
- optimizer_literal_obj_info(
- info,
- opline->op1_type,
- opline->op1,
- opline->op2.constant,
- LITERAL_PROPERTY, 2, 1,
- op_array);
+ LITERAL_INFO(opline->op2.constant, LITERAL_PROPERTY, 1);
}
break;
case ZEND_ASSIGN_ADD:
@@ -270,47 +241,30 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
case ZEND_ASSIGN_BW_XOR:
if (opline->op2_type == 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);
+ LITERAL_INFO(opline->op2.constant, LITERAL_PROPERTY, 1);
} else {
- LITERAL_INFO(opline->op2.constant, LITERAL_VALUE, 1, 0, 1);
+ LITERAL_INFO(opline->op2.constant, LITERAL_VALUE, 1);
}
}
break;
case ZEND_BIND_GLOBAL:
- LITERAL_INFO(opline->op2.constant, LITERAL_GLOBAL, 0, 1, 1);
+ LITERAL_INFO(opline->op2.constant, LITERAL_GLOBAL, 1);
break;
case ZEND_RECV_INIT:
- LITERAL_INFO(opline->op2.constant, LITERAL_VALUE, 0, 0, 1);
- if (Z_CACHE_SLOT(op_array->literals[opline->op2.constant]) != (uint32_t)-1) {
- Z_CACHE_SLOT(op_array->literals[opline->op2.constant]) = cache_size;
- cache_size += sizeof(void *);
- }
+ LITERAL_INFO(opline->op2.constant, LITERAL_VALUE, 1);
break;
case ZEND_DECLARE_FUNCTION:
case ZEND_DECLARE_CLASS:
case ZEND_DECLARE_INHERITED_CLASS:
case ZEND_DECLARE_INHERITED_CLASS_DELAYED:
- LITERAL_INFO(opline->op1.constant, LITERAL_VALUE, 0, 0, 2);
+ LITERAL_INFO(opline->op1.constant, LITERAL_VALUE, 2);
break;
- case ZEND_RECV:
- case ZEND_RECV_VARIADIC:
- case ZEND_VERIFY_RETURN_TYPE:
- if (opline->op2.num != (uint32_t)-1) {
- opline->op2.num = cache_size;
- cache_size += sizeof(void *);
- }
default:
if (opline->op1_type == IS_CONST) {
- LITERAL_INFO(opline->op1.constant, LITERAL_VALUE, 1, 0, 1);
+ LITERAL_INFO(opline->op1.constant, LITERAL_VALUE, 1);
}
if (opline->op2_type == IS_CONST) {
- LITERAL_INFO(opline->op2.constant, LITERAL_VALUE, 1, 0, 1);
+ LITERAL_INFO(opline->op2.constant, LITERAL_VALUE, 1);
}
break;
}
@@ -350,26 +304,15 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
}
switch (Z_TYPE(op_array->literals[i])) {
case IS_NULL:
- /* Only checking MAY_MERGE for IS_NULL here
- * is because only IS_NULL can be default value for class type hinting(RECV_INIT). */
- if ((info[i].flags & LITERAL_MAY_MERGE)) {
- 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;
- } else {
- map[i] = j;
+ 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_FALSE:
if (l_false < 0) {
@@ -422,34 +365,20 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
}
break;
case IS_STRING:
- if (info[i].flags & LITERAL_MAY_MERGE) {
- if (info[i].flags & LITERAL_EX_OBJ) {
- int key_len = sizeof("$this->") - 1 + Z_STRLEN(op_array->literals[i]);
- key = zend_string_alloc(key_len, 0);
- memcpy(ZSTR_VAL(key), "$this->", sizeof("$this->") - 1);
- memcpy(ZSTR_VAL(key) + sizeof("$this->") - 1, Z_STRVAL(op_array->literals[i]), Z_STRLEN(op_array->literals[i]) + 1);
- ZSTR_LEN(key) = key_len;
- } else if (info[i].flags & LITERAL_EX_CLASS) {
- int key_len;
- zval *class_name = &op_array->literals[(info[i].u.num < i) ? map[info[i].u.num] : info[i].u.num];
- key_len = Z_STRLEN_P(class_name) + sizeof("::") - 1 + Z_STRLEN(op_array->literals[i]);
- key = zend_string_alloc(key_len, 0);
- memcpy(ZSTR_VAL(key), Z_STRVAL_P(class_name), Z_STRLEN_P(class_name));
- memcpy(ZSTR_VAL(key) + Z_STRLEN_P(class_name), "::", sizeof("::") - 1);
- memcpy(ZSTR_VAL(key) + Z_STRLEN_P(class_name) + sizeof("::") - 1,
- Z_STRVAL(op_array->literals[i]),
- Z_STRLEN(op_array->literals[i]) + 1);
- } else {
- key = zend_string_init(Z_STRVAL(op_array->literals[i]), Z_STRLEN(op_array->literals[i]), 0);
- }
- ZSTR_H(key) = zend_hash_func(ZSTR_VAL(key), ZSTR_LEN(key));
- ZSTR_H(key) += info[i].flags;
+ if (LITERAL_NUM_RELATED(info[i].flags) == 1) {
+ key = zend_string_copy(Z_STR(op_array->literals[i]));
+ } else {
+ key = zend_string_init(Z_STRVAL(op_array->literals[i]), Z_STRLEN(op_array->literals[i]), 0);
+ ZSTR_H(key) = ZSTR_HASH(Z_STR(op_array->literals[i])) +
+ LITERAL_NUM_RELATED(info[i].flags) - 1;
}
- if ((info[i].flags & LITERAL_MAY_MERGE) &&
- (pos = zend_hash_find(&hash, key)) != NULL &&
- Z_TYPE(op_array->literals[i]) == Z_TYPE(op_array->literals[Z_LVAL_P(pos)]) &&
- info[i].flags == info[Z_LVAL_P(pos)].flags) {
-
+ pos = zend_hash_find(&hash, key);
+ if (pos != NULL &&
+ Z_TYPE(op_array->literals[Z_LVAL_P(pos)]) == IS_STRING &&
+ LITERAL_NUM_RELATED(info[i].flags) == LITERAL_NUM_RELATED(info[Z_LVAL_P(pos)].flags) &&
+ (LITERAL_NUM_RELATED(info[i].flags) != 2 ||
+ ((info[i].flags & LITERAL_KIND_MASK) != LITERAL_VALUE &&
+ (info[Z_LVAL_P(pos)].flags & LITERAL_KIND_MASK) != LITERAL_VALUE))) {
zend_string_release(key);
map[i] = Z_LVAL_P(pos);
zval_ptr_dtor_nogc(&op_array->literals[i]);
@@ -461,19 +390,13 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
}
} else {
map[i] = j;
- if (info[i].flags & LITERAL_MAY_MERGE) {
- ZVAL_LONG(&zv, j);
- zend_hash_add_new(&hash, key, &zv);
- zend_string_release(key);
- }
+ ZVAL_LONG(&zv, j);
+ zend_hash_add_new(&hash, key, &zv);
+ zend_string_release(key);
if (i != j) {
op_array->literals[j] = op_array->literals[i];
info[j] = info[i];
}
- if (LITERAL_NUM_SLOTS(info[i].flags)) {
- Z_CACHE_SLOT(op_array->literals[j]) = cache_size;
- cache_size += LITERAL_NUM_SLOTS(info[i].flags) * sizeof(void*);
- }
j++;
n = LITERAL_NUM_RELATED(info[i].flags);
while (n > 1) {
@@ -511,11 +434,19 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
break;
}
}
- zend_hash_destroy(&hash);
+ zend_hash_clean(&hash);
op_array->last_literal = j;
- op_array->cache_size = cache_size;
- /* Update opcodes to use new literals table */
+ const_slot = zend_arena_alloc(&ctx->arena, j * 6 * sizeof(int));
+ memset(const_slot, -1, j * 6 * sizeof(int));
+ class_slot = const_slot + j;
+ func_slot = class_slot + j;
+ bind_var_slot = func_slot + j;
+ property_slot = bind_var_slot + j;
+ method_slot = property_slot + j;
+
+ /* Update opcodes to use new literals table */
+ cache_size = 0;
opline = op_array->opcodes;
end = opline + op_array->last;
while (opline < end) {
@@ -525,8 +456,288 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
if (opline->op2_type == IS_CONST) {
opline->op2.constant = map[opline->op2.constant];
}
+ switch (opline->opcode) {
+ case ZEND_RECV_INIT:
+ if (class_name_type_hint(op_array, opline->op1.num)) {
+ opline->extended_value = cache_size;
+ cache_size += sizeof(void *);
+ }
+ break;
+ case ZEND_RECV:
+ case ZEND_RECV_VARIADIC:
+ if (class_name_type_hint(op_array, opline->op1.num)) {
+ opline->op2.num = cache_size;
+ cache_size += sizeof(void *);
+ }
+ break;
+ case ZEND_VERIFY_RETURN_TYPE:
+ if (class_name_type_hint(op_array, 0)) {
+ opline->op2.num = cache_size;
+ cache_size += sizeof(void *);
+ }
+ break;
+ case ZEND_ASSIGN_ADD:
+ case ZEND_ASSIGN_SUB:
+ case ZEND_ASSIGN_MUL:
+ case ZEND_ASSIGN_DIV:
+ case ZEND_ASSIGN_POW:
+ 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 (opline->extended_value != ZEND_ASSIGN_OBJ) {
+ break;
+ }
+ if (opline->op2_type == IS_CONST) {
+ // op2 property
+ if (opline->op1_type == IS_UNUSED &&
+ property_slot[opline->op2.constant] >= 0) {
+ (opline+1)->extended_value = property_slot[opline->op2.constant];
+ } else {
+ (opline+1)->extended_value = cache_size;
+ cache_size += 2 * sizeof(void *);
+ if (opline->op1_type == IS_UNUSED) {
+ property_slot[opline->op2.constant] = (opline+1)->extended_value;
+ }
+ }
+ }
+ 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:
+ if (opline->op2_type == IS_CONST) {
+ // op2 property
+ if (opline->op1_type == IS_UNUSED &&
+ property_slot[opline->op2.constant] >= 0) {
+ opline->extended_value = property_slot[opline->op2.constant];
+ } else {
+ opline->extended_value = cache_size;
+ cache_size += 2 * sizeof(void *);
+ if (opline->op1_type == IS_UNUSED) {
+ property_slot[opline->op2.constant] = opline->extended_value;
+ }
+ }
+ }
+ break;
+ case ZEND_ISSET_ISEMPTY_PROP_OBJ:
+ if (opline->op2_type == IS_CONST) {
+ // op2 property
+ if (opline->op1_type == IS_UNUSED &&
+ property_slot[opline->op2.constant] >= 0) {
+ opline->extended_value = property_slot[opline->op2.constant] | (opline->extended_value & ZEND_ISSET);
+ } else {
+ opline->extended_value = cache_size | (opline->extended_value & ZEND_ISSET);
+ cache_size += 2 * sizeof(void *);
+ if (opline->op1_type == IS_UNUSED) {
+ property_slot[opline->op2.constant] = opline->extended_value & ~ZEND_ISSET;
+ }
+ }
+ }
+ break;
+ case ZEND_INIT_FCALL:
+ case ZEND_INIT_FCALL_BY_NAME:
+ case ZEND_INIT_NS_FCALL_BY_NAME:
+ // op2 func
+ if (func_slot[opline->op2.constant] >= 0) {
+ opline->result.num = func_slot[opline->op2.constant];
+ } else {
+ opline->result.num = cache_size;
+ cache_size += sizeof(void *);
+ func_slot[opline->op2.constant] = opline->result.num;
+ }
+ break;
+ case ZEND_INIT_METHOD_CALL:
+ if (opline->op2_type == IS_CONST) {
+ // op2 method
+ if (opline->op1_type == IS_UNUSED &&
+ method_slot[opline->op2.constant] >= 0) {
+ opline->result.num = method_slot[opline->op2.constant];
+ } else {
+ opline->result.num = cache_size;
+ cache_size += 2 * sizeof(void *);
+ if (opline->op1_type == IS_UNUSED) {
+ method_slot[opline->op2.constant] = opline->result.num;
+ }
+ }
+ }
+ break;
+ case ZEND_INIT_STATIC_METHOD_CALL:
+ if (opline->op2_type == IS_CONST) {
+ // op2 static method
+ if (opline->op1_type == IS_CONST) {
+ opline->result.num = add_static_slot(&hash, op_array,
+ opline->op1.constant,
+ opline->op2.constant,
+ LITERAL_STATIC_METHOD,
+ &cache_size);
+ } else {
+ opline->result.num = cache_size;
+ cache_size += 2 * sizeof(void *);
+ }
+ } else if (opline->op1_type == IS_CONST) {
+ // op1 class
+ if (class_slot[opline->op1.constant] >= 0) {
+ opline->result.num = class_slot[opline->op1.constant];
+ } else {
+ opline->result.num = cache_size;
+ cache_size += sizeof(void *);
+ class_slot[opline->op1.constant] = opline->result.num;
+ }
+ }
+ break;
+ case ZEND_DEFINED:
+ // op1 const
+ if (const_slot[opline->op1.constant] >= 0) {
+ opline->extended_value = const_slot[opline->op1.constant];
+ } else {
+ opline->extended_value = cache_size;
+ cache_size += sizeof(void *);
+ const_slot[opline->op1.constant] = opline->extended_value;
+ }
+ break;
+ case ZEND_FETCH_CONSTANT:
+ // op2 const
+ if (const_slot[opline->op2.constant] >= 0) {
+ opline->extended_value = const_slot[opline->op2.constant];
+ } else {
+ opline->extended_value = cache_size;
+ cache_size += sizeof(void *);
+ const_slot[opline->op2.constant] = opline->extended_value;
+ }
+ break;
+ case ZEND_FETCH_CLASS_CONSTANT:
+ if (opline->op1_type == IS_CONST) {
+ // op1/op2 class_const
+ opline->extended_value = add_static_slot(&hash, op_array,
+ opline->op1.constant,
+ opline->op2.constant,
+ LITERAL_CLASS_CONST,
+ &cache_size);
+ } else {
+ opline->extended_value = cache_size;
+ cache_size += 2 * sizeof(void *);
+ }
+ break;
+ case ZEND_FETCH_STATIC_PROP_R:
+ case ZEND_FETCH_STATIC_PROP_W:
+ case ZEND_FETCH_STATIC_PROP_RW:
+ case ZEND_FETCH_STATIC_PROP_IS:
+ case ZEND_FETCH_STATIC_PROP_UNSET:
+ case ZEND_FETCH_STATIC_PROP_FUNC_ARG:
+ case ZEND_UNSET_STATIC_PROP:
+ if (opline->op1_type == IS_CONST) {
+ // op1 static property
+ if (opline->op2_type == IS_CONST) {
+ opline->extended_value = add_static_slot(&hash, op_array,
+ opline->op2.constant,
+ opline->op1.constant,
+ LITERAL_STATIC_PROPERTY,
+ &cache_size);
+ } else {
+ opline->extended_value = cache_size;
+ cache_size += 2 * sizeof(void *);
+ }
+ } else if (opline->op2_type == IS_CONST) {
+ // op2 class
+ if (class_slot[opline->op2.constant] >= 0) {
+ opline->extended_value = class_slot[opline->op2.constant];
+ } else {
+ opline->extended_value = cache_size;
+ cache_size += sizeof(void *);
+ class_slot[opline->op2.constant] = opline->extended_value;
+ }
+ }
+ break;
+ case ZEND_ISSET_ISEMPTY_STATIC_PROP:
+ if (opline->op1_type == IS_CONST) {
+ // op1 static property
+ if (opline->op2_type == IS_CONST) {
+ opline->extended_value = add_static_slot(&hash, op_array,
+ opline->op2.constant,
+ opline->op1.constant,
+ LITERAL_STATIC_PROPERTY,
+ &cache_size) | (opline->extended_value & ZEND_ISSET);
+ } else {
+ opline->extended_value = cache_size | (opline->extended_value & ZEND_ISSET);
+ cache_size += 2 * sizeof(void *);
+ }
+ } else if (opline->op2_type == IS_CONST) {
+ // op2 class
+ if (class_slot[opline->op2.constant] >= 0) {
+ opline->extended_value = class_slot[opline->op2.constant] | (opline->extended_value & ZEND_ISSET);
+ } else {
+ opline->extended_value = cache_size | (opline->extended_value & ZEND_ISSET);
+ cache_size += sizeof(void *);
+ class_slot[opline->op2.constant] = opline->extended_value & ~ZEND_ISSET;
+ }
+ }
+ break;
+ case ZEND_FETCH_CLASS:
+ case ZEND_ADD_INTERFACE:
+ case ZEND_ADD_TRAIT:
+ case ZEND_INSTANCEOF:
+ if (opline->op2_type == IS_CONST) {
+ // op2 class
+ if (class_slot[opline->op2.constant] >= 0) {
+ opline->extended_value = class_slot[opline->op2.constant];
+ } else {
+ opline->extended_value = cache_size;
+ cache_size += sizeof(void *);
+ class_slot[opline->op2.constant] = opline->extended_value;
+ }
+ }
+ break;
+ case ZEND_NEW:
+ if (opline->op1_type == IS_CONST) {
+ // op1 class
+ if (class_slot[opline->op1.constant] >= 0) {
+ opline->op2.num = class_slot[opline->op1.constant];
+ } else {
+ opline->op2.num = cache_size;
+ cache_size += sizeof(void *);
+ class_slot[opline->op1.constant] = opline->op2.num;
+ }
+ }
+ break;
+ case ZEND_CATCH:
+ if (opline->op1_type == IS_CONST) {
+ // op1 class
+ if (class_slot[opline->op1.constant] >= 0) {
+ opline->extended_value = class_slot[opline->op1.constant] | (opline->extended_value & ZEND_LAST_CATCH);
+ } else {
+ opline->extended_value = cache_size | (opline->extended_value & ZEND_LAST_CATCH);
+ cache_size += sizeof(void *);
+ class_slot[opline->op1.constant] = opline->extended_value & ~ZEND_LAST_CATCH;
+ }
+ }
+ break;
+ case ZEND_BIND_GLOBAL:
+ // op2 bind var
+ if (bind_var_slot[opline->op2.constant] >= 0) {
+ opline->extended_value = bind_var_slot[opline->op2.constant];
+ } else {
+ opline->extended_value = cache_size;
+ cache_size += sizeof(void *);
+ bind_var_slot[opline->op2.constant] = opline->extended_value;
+ }
+ break;
+ }
opline++;
}
+ op_array->cache_size = cache_size;
+ zend_hash_destroy(&hash);
zend_arena_release(&ctx->arena, checkpoint);
#if DEBUG_COMPACT_LITERALS
diff --git a/ext/opcache/Optimizer/dfa_pass.c b/ext/opcache/Optimizer/dfa_pass.c
index 13aec486f6..4a7ba6ba69 100644
--- a/ext/opcache/Optimizer/dfa_pass.c
+++ b/ext/opcache/Optimizer/dfa_pass.c
@@ -552,7 +552,7 @@ static void zend_ssa_replace_control_link(zend_op_array *op_array, zend_ssa *ssa
}
break;
case ZEND_CATCH:
- if (opline->extended_value != ZEND_LAST_CATCH) {
+ if (!(opline->extended_value & ZEND_LAST_CATCH)) {
if (ZEND_OP2_JMP_ADDR(opline) == op_array->opcodes + old->start) {
ZEND_SET_OP_JMP_ADDR(opline, opline->op2, op_array->opcodes + dst->start);
}
diff --git a/ext/opcache/Optimizer/optimize_func_calls.c b/ext/opcache/Optimizer/optimize_func_calls.c
index 32de6ba35c..1642994765 100644
--- a/ext/opcache/Optimizer/optimize_func_calls.c
+++ b/ext/opcache/Optimizer/optimize_func_calls.c
@@ -193,14 +193,12 @@ void zend_optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx)
} else if (fcall->opcode == ZEND_INIT_FCALL_BY_NAME) {
fcall->opcode = ZEND_INIT_FCALL;
fcall->op1.num = zend_vm_calc_used_stack(fcall->extended_value, call_stack[call].func);
- Z_CACHE_SLOT(op_array->literals[fcall->op2.constant + 1]) = Z_CACHE_SLOT(op_array->literals[fcall->op2.constant]);
literal_dtor(&ZEND_OP2_LITERAL(fcall));
fcall->op2.constant = fcall->op2.constant + 1;
opline->opcode = zend_get_call_op(fcall, call_stack[call].func);
} else if (fcall->opcode == ZEND_INIT_NS_FCALL_BY_NAME) {
fcall->opcode = ZEND_INIT_FCALL;
fcall->op1.num = zend_vm_calc_used_stack(fcall->extended_value, call_stack[call].func);
- Z_CACHE_SLOT(op_array->literals[fcall->op2.constant + 1]) = Z_CACHE_SLOT(op_array->literals[fcall->op2.constant]);
literal_dtor(&op_array->literals[fcall->op2.constant]);
literal_dtor(&op_array->literals[fcall->op2.constant + 2]);
fcall->op2.constant = fcall->op2.constant + 1;
diff --git a/ext/opcache/Optimizer/sccp.c b/ext/opcache/Optimizer/sccp.c
index 1b2623c307..ca5b2213f0 100644
--- a/ext/opcache/Optimizer/sccp.c
+++ b/ext/opcache/Optimizer/sccp.c
@@ -438,7 +438,7 @@ static inline int ct_eval_isset_dim(zval *result, uint32_t extended_value, zval
// TODO
return FAILURE;
} else {
- ZVAL_BOOL(result, extended_value != ZEND_ISSET);
+ ZVAL_BOOL(result, !(extended_value & ZEND_ISSET));
return SUCCESS;
}
}
@@ -592,7 +592,7 @@ static inline int ct_eval_isset_obj(zval *result, uint32_t extended_value, zval
}
return SUCCESS;
} else {
- ZVAL_BOOL(result, extended_value != ZEND_ISSET);
+ ZVAL_BOOL(result, !(extended_value & ZEND_ISSET));
return SUCCESS;
}
}
diff --git a/ext/opcache/Optimizer/zend_cfg.c b/ext/opcache/Optimizer/zend_cfg.c
index a2d021516d..6c29b37c41 100644
--- a/ext/opcache/Optimizer/zend_cfg.c
+++ b/ext/opcache/Optimizer/zend_cfg.c
@@ -385,7 +385,7 @@ int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t b
BB_START(i + 1);
break;
case ZEND_CATCH:
- if (opline->extended_value != ZEND_LAST_CATCH) {
+ if (!(opline->extended_value & ZEND_LAST_CATCH)) {
BB_START(OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes);
}
BB_START(i + 1);
@@ -546,7 +546,7 @@ int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t b
block->successors[1] = j + 1;
break;
case ZEND_CATCH:
- if (opline->extended_value != ZEND_LAST_CATCH) {
+ if (!(opline->extended_value & ZEND_LAST_CATCH)) {
block->successors_count = 2;
block->successors[0] = block_map[OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes];
block->successors[1] = j + 1;
diff --git a/ext/opcache/Optimizer/zend_dump.c b/ext/opcache/Optimizer/zend_dump.c
index 22e149ae55..7fb55355fd 100644
--- a/ext/opcache/Optimizer/zend_dump.c
+++ b/ext/opcache/Optimizer/zend_dump.c
@@ -674,7 +674,7 @@ static void zend_dump_op(const zend_op_array *op_array, const zend_basic_block *
} else {
uint32_t op2_flags = ZEND_VM_OP2_FLAGS(flags);
if (ZEND_VM_OP_JMP_ADDR == (op2_flags & ZEND_VM_OP_MASK)) {
- if (opline->opcode != ZEND_CATCH || opline->extended_value != ZEND_LAST_CATCH) {
+ if (opline->opcode != ZEND_CATCH || !(opline->extended_value & ZEND_LAST_CATCH)) {
if (b) {
fprintf(stderr, " BB%d", b->successors[n++]);
} else {
diff --git a/ext/opcache/Optimizer/zend_optimizer.c b/ext/opcache/Optimizer/zend_optimizer.c
index f9b21ff19e..07860f3998 100644
--- a/ext/opcache/Optimizer/zend_optimizer.c
+++ b/ext/opcache/Optimizer/zend_optimizer.c
@@ -206,7 +206,6 @@ int zend_optimizer_add_literal(zend_op_array *op_array, zval *zv)
op_array->last_literal++;
op_array->literals = (zval*)erealloc(op_array->literals, op_array->last_literal * sizeof(zval));
ZVAL_COPY_VALUE(&op_array->literals[i], zv);
- Z_CACHE_SLOT(op_array->literals[i]) = -1;
return i;
}
@@ -232,13 +231,10 @@ static inline void drop_leading_backslash(zval *val) {
}
}
-static inline void alloc_cache_slots_op1(zend_op_array *op_array, zend_op *opline, uint32_t num) {
- Z_CACHE_SLOT(op_array->literals[opline->op1.constant]) = op_array->cache_size;
- op_array->cache_size += num * sizeof(void *);
-}
-static inline void alloc_cache_slots_op2(zend_op_array *op_array, zend_op *opline, uint32_t num) {
- Z_CACHE_SLOT(op_array->literals[opline->op2.constant]) = op_array->cache_size;
+static inline uint32_t alloc_cache_slots(zend_op_array *op_array, uint32_t num) {
+ uint32_t ret = op_array->cache_size;
op_array->cache_size += num * sizeof(void *);
+ return ret;
}
#define REQUIRES_STRING(val) do { \
@@ -275,15 +271,43 @@ int zend_optimizer_update_op1_const(zend_op_array *op_array,
case ZEND_RETURN_BY_REF:
case ZEND_INSTANCEOF:
return 0;
- case ZEND_INIT_STATIC_METHOD_CALL:
case ZEND_CATCH:
- case ZEND_FETCH_CLASS_CONSTANT:
+ REQUIRES_STRING(val);
+ drop_leading_backslash(val);
+ opline->op1.constant = zend_optimizer_add_literal(op_array, val);
+ opline->extended_value = alloc_cache_slots(op_array, 1) | (opline->extended_value & ZEND_LAST_CATCH);
+ zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val)));
+ break;
case ZEND_DEFINED:
+ REQUIRES_STRING(val);
+ drop_leading_backslash(val);
+ opline->op1.constant = zend_optimizer_add_literal(op_array, val);
+ opline->extended_value = alloc_cache_slots(op_array, 1);
+ zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val)));
+ break;
case ZEND_NEW:
REQUIRES_STRING(val);
drop_leading_backslash(val);
opline->op1.constant = zend_optimizer_add_literal(op_array, val);
- alloc_cache_slots_op1(op_array, opline, 1);
+ opline->op2.num = alloc_cache_slots(op_array, 1);
+ zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val)));
+ break;
+ case ZEND_INIT_STATIC_METHOD_CALL:
+ REQUIRES_STRING(val);
+ drop_leading_backslash(val);
+ opline->op1.constant = zend_optimizer_add_literal(op_array, val);
+ if (opline->op2_type != IS_CONST) {
+ opline->result.num = alloc_cache_slots(op_array, 1);
+ }
+ zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val)));
+ break;
+ case ZEND_FETCH_CLASS_CONSTANT:
+ REQUIRES_STRING(val);
+ drop_leading_backslash(val);
+ opline->op1.constant = zend_optimizer_add_literal(op_array, val);
+ if (opline->op2_type != IS_CONST) {
+ opline->extended_value = alloc_cache_slots(op_array, 1);
+ }
zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val)));
break;
case ZEND_FETCH_STATIC_PROP_R:
@@ -292,9 +316,23 @@ int zend_optimizer_update_op1_const(zend_op_array *op_array,
case ZEND_FETCH_STATIC_PROP_IS:
case ZEND_FETCH_STATIC_PROP_UNSET:
case ZEND_FETCH_STATIC_PROP_FUNC_ARG:
+ case ZEND_UNSET_STATIC_PROP:
TO_STRING_NOWARN(val);
opline->op1.constant = zend_optimizer_add_literal(op_array, val);
- alloc_cache_slots_op1(op_array, opline, 2);
+ if (opline->op2_type == IS_CONST && opline->extended_value + sizeof(void*) == op_array->cache_size) {
+ op_array->cache_size += sizeof(void *);
+ } else {
+ opline->extended_value = alloc_cache_slots(op_array, 2);
+ }
+ break;
+ case ZEND_ISSET_ISEMPTY_STATIC_PROP:
+ TO_STRING_NOWARN(val);
+ opline->op1.constant = zend_optimizer_add_literal(op_array, val);
+ if (opline->op2_type == IS_CONST && (opline->extended_value & ~ZEND_ISSET) + sizeof(void*) == op_array->cache_size) {
+ op_array->cache_size += sizeof(void *);
+ } else {
+ opline->extended_value = alloc_cache_slots(op_array, 2) | (opline->extended_value & ZEND_ISSET);
+ }
break;
case ZEND_SEND_VAR:
opline->opcode = ZEND_SEND_VAL;
@@ -351,11 +389,22 @@ int zend_optimizer_update_op2_const(zend_op_array *op_array,
(opline + 1)->op2.var == opline->result.var) {
return 0;
}
- case ZEND_INIT_FCALL_BY_NAME:
- /*case ZEND_INIT_NS_FCALL_BY_NAME:*/
case ZEND_ADD_INTERFACE:
case ZEND_ADD_TRAIT:
case ZEND_INSTANCEOF:
+ REQUIRES_STRING(val);
+ drop_leading_backslash(val);
+ opline->op2.constant = zend_optimizer_add_literal(op_array, val);
+ zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val)));
+ opline->extended_value = alloc_cache_slots(op_array, 1);
+ break;
+ case ZEND_INIT_FCALL_BY_NAME:
+ REQUIRES_STRING(val);
+ drop_leading_backslash(val);
+ opline->op2.constant = zend_optimizer_add_literal(op_array, val);
+ zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val)));
+ opline->result.num = alloc_cache_slots(op_array, 1);
+ break;
case ZEND_FETCH_STATIC_PROP_R:
case ZEND_FETCH_STATIC_PROP_W:
case ZEND_FETCH_STATIC_PROP_RW:
@@ -363,12 +412,22 @@ int zend_optimizer_update_op2_const(zend_op_array *op_array,
case ZEND_FETCH_STATIC_PROP_UNSET:
case ZEND_FETCH_STATIC_PROP_FUNC_ARG:
case ZEND_UNSET_STATIC_PROP:
+ REQUIRES_STRING(val);
+ drop_leading_backslash(val);
+ opline->op2.constant = zend_optimizer_add_literal(op_array, val);
+ zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val)));
+ if (opline->op1_type != IS_CONST) {
+ opline->extended_value = alloc_cache_slots(op_array, 1);
+ }
+ break;
case ZEND_ISSET_ISEMPTY_STATIC_PROP:
REQUIRES_STRING(val);
drop_leading_backslash(val);
opline->op2.constant = zend_optimizer_add_literal(op_array, val);
zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val)));
- alloc_cache_slots_op2(op_array, opline, 1);
+ if (opline->op1_type != IS_CONST) {
+ opline->extended_value = alloc_cache_slots(op_array, 1) | (opline->extended_value & ZEND_ISSET);
+ }
break;
case ZEND_INIT_FCALL:
REQUIRES_STRING(val);
@@ -380,7 +439,7 @@ int zend_optimizer_update_op2_const(zend_op_array *op_array,
val = &tmp;
}
opline->op2.constant = zend_optimizer_add_literal(op_array, val);
- alloc_cache_slots_op2(op_array, opline, 1);
+ opline->result.num = alloc_cache_slots(op_array, 1);
break;
case ZEND_INIT_DYNAMIC_CALL:
if (Z_TYPE_P(val) == IS_STRING) {
@@ -398,19 +457,25 @@ int zend_optimizer_update_op2_const(zend_op_array *op_array,
drop_leading_backslash(val);
opline->op2.constant = zend_optimizer_add_literal(op_array, val);
zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val)));
- alloc_cache_slots_op2(op_array, opline, 1);
+ opline->result.num = alloc_cache_slots(op_array, 1);
} else {
opline->op2.constant = zend_optimizer_add_literal(op_array, val);
}
break;
case ZEND_INIT_METHOD_CALL:
+ REQUIRES_STRING(val);
+ opline->op2.constant = zend_optimizer_add_literal(op_array, val);
+ zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val)));
+ opline->result.num = alloc_cache_slots(op_array, 2);
+ break;
case ZEND_INIT_STATIC_METHOD_CALL:
REQUIRES_STRING(val);
opline->op2.constant = zend_optimizer_add_literal(op_array, val);
zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val)));
- alloc_cache_slots_op2(op_array, opline, 2);
+ if (opline->op1_type != IS_CONST) {
+ opline->result.num = alloc_cache_slots(op_array, 2);
+ }
break;
- /*case ZEND_FETCH_CLASS_CONSTANT:*/
case ZEND_ASSIGN_OBJ:
case ZEND_FETCH_OBJ_R:
case ZEND_FETCH_OBJ_W:
@@ -423,10 +488,14 @@ int zend_optimizer_update_op2_const(zend_op_array *op_array,
case ZEND_PRE_DEC_OBJ:
case ZEND_POST_INC_OBJ:
case ZEND_POST_DEC_OBJ:
+ TO_STRING_NOWARN(val);
+ opline->op2.constant = zend_optimizer_add_literal(op_array, val);
+ opline->extended_value = alloc_cache_slots(op_array, 2);
+ break;
case ZEND_ISSET_ISEMPTY_PROP_OBJ:
TO_STRING_NOWARN(val);
opline->op2.constant = zend_optimizer_add_literal(op_array, val);
- alloc_cache_slots_op2(op_array, opline, 2);
+ opline->extended_value = alloc_cache_slots(op_array, 2) | (opline->extended_value & ZEND_ISSET);
break;
case ZEND_ASSIGN_ADD:
case ZEND_ASSIGN_SUB:
@@ -443,7 +512,7 @@ int zend_optimizer_update_op2_const(zend_op_array *op_array,
if (opline->extended_value == ZEND_ASSIGN_OBJ) {
TO_STRING_NOWARN(val);
opline->op2.constant = zend_optimizer_add_literal(op_array, val);
- alloc_cache_slots_op2(op_array, opline, 2);
+ (opline+1)->extended_value = alloc_cache_slots(op_array, 2);
} else {
opline->op2.constant = zend_optimizer_add_literal(op_array, val);
}
@@ -766,7 +835,7 @@ void zend_optimizer_migrate_jump(zend_op_array *op_array, zend_op *new_opline, z
new_opline->extended_value = ZEND_OPLINE_NUM_TO_OFFSET(op_array, new_opline, ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value));
break;
case ZEND_CATCH:
- if (opline->extended_value != ZEND_LAST_CATCH) {
+ if (!(opline->extended_value & ZEND_LAST_CATCH)) {
ZEND_SET_OP_JMP_ADDR(new_opline, new_opline->op2, ZEND_OP2_JMP_ADDR(opline));
}
break;
@@ -806,7 +875,7 @@ void zend_optimizer_shift_jump(zend_op_array *op_array, zend_op *opline, uint32_
ZEND_SET_OP_JMP_ADDR(opline, opline->op2, ZEND_OP2_JMP_ADDR(opline) - shiftlist[ZEND_OP2_JMP_ADDR(opline) - op_array->opcodes]);
break;
case ZEND_CATCH:
- if (opline->extended_value != ZEND_LAST_CATCH) {
+ if (!(opline->extended_value & ZEND_LAST_CATCH)) {
ZEND_SET_OP_JMP_ADDR(opline, opline->op2, ZEND_OP2_JMP_ADDR(opline) - shiftlist[ZEND_OP2_JMP_ADDR(opline) - op_array->opcodes]);
}
break;
@@ -1174,7 +1243,7 @@ static void zend_redo_pass_two(zend_op_array *op_array)
opline->op2.jmp_addr = &op_array->opcodes[opline->op2.jmp_addr - old_opcodes];
break;
case ZEND_CATCH:
- if (opline->extended_value != ZEND_LAST_CATCH) {
+ if (!(opline->extended_value & ZEND_LAST_CATCH)) {
opline->op2.jmp_addr = &op_array->opcodes[opline->op2.jmp_addr - old_opcodes];
}
break;
@@ -1260,7 +1329,7 @@ static void zend_redo_pass_two_ex(zend_op_array *op_array, zend_ssa *ssa)
opline->op2.jmp_addr = &op_array->opcodes[opline->op2.jmp_addr - old_opcodes];
break;
case ZEND_CATCH:
- if (opline->extended_value != ZEND_LAST_CATCH) {
+ if (!(opline->extended_value & ZEND_LAST_CATCH)) {
opline->op2.jmp_addr = &op_array->opcodes[opline->op2.jmp_addr - old_opcodes];
}
break;
diff --git a/ext/opcache/zend_file_cache.c b/ext/opcache/zend_file_cache.c
index db926a5172..de54949901 100644
--- a/ext/opcache/zend_file_cache.c
+++ b/ext/opcache/zend_file_cache.c
@@ -447,7 +447,7 @@ static void zend_file_cache_serialize_op_array(zend_op_array *op_arra
SERIALIZE_PTR(opline->op2.jmp_addr);
break;
case ZEND_CATCH:
- if (opline->extended_value != ZEND_LAST_CATCH) {
+ if (!(opline->extended_value & ZEND_LAST_CATCH)) {
SERIALIZE_PTR(opline->op2.jmp_addr);
}
break;
@@ -1053,7 +1053,7 @@ static void zend_file_cache_unserialize_op_array(zend_op_array *op_arr
UNSERIALIZE_PTR(opline->op2.jmp_addr);
break;
case ZEND_CATCH:
- if (opline->extended_value != ZEND_LAST_CATCH) {
+ if (!(opline->extended_value & ZEND_LAST_CATCH)) {
UNSERIALIZE_PTR(opline->op2.jmp_addr);
}
break;
diff --git a/ext/opcache/zend_persist.c b/ext/opcache/zend_persist.c
index a2549308ad..8c16538207 100644
--- a/ext/opcache/zend_persist.c
+++ b/ext/opcache/zend_persist.c
@@ -453,7 +453,7 @@ static void zend_persist_op_array_ex(zend_op_array *op_array, zend_persistent_sc
opline->op2.jmp_addr = &new_opcodes[opline->op2.jmp_addr - op_array->opcodes];
break;
case ZEND_CATCH:
- if (opline->extended_value != ZEND_LAST_CATCH) {
+ if (!(opline->extended_value & ZEND_LAST_CATCH)) {
opline->op2.jmp_addr = &new_opcodes[opline->op2.jmp_addr - op_array->opcodes];
}
break;