summaryrefslogtreecommitdiff
path: root/ext/opcache/Optimizer
diff options
context:
space:
mode:
Diffstat (limited to 'ext/opcache/Optimizer')
-rw-r--r--ext/opcache/Optimizer/block_pass.c1081
-rw-r--r--ext/opcache/Optimizer/compact_literals.c15
-rw-r--r--ext/opcache/Optimizer/dce.c2
-rw-r--r--ext/opcache/Optimizer/dfa_pass.c112
-rw-r--r--ext/opcache/Optimizer/escape_analysis.c8
-rw-r--r--ext/opcache/Optimizer/optimize_func_calls.c6
-rw-r--r--ext/opcache/Optimizer/pass1.c (renamed from ext/opcache/Optimizer/pass1_5.c)186
-rw-r--r--ext/opcache/Optimizer/pass2.c225
-rw-r--r--ext/opcache/Optimizer/pass3.c563
-rw-r--r--ext/opcache/Optimizer/sccp.c14
-rw-r--r--ext/opcache/Optimizer/ssa_integrity.c2
-rw-r--r--ext/opcache/Optimizer/zend_call_graph.c19
-rw-r--r--ext/opcache/Optimizer/zend_call_graph.h3
-rw-r--r--ext/opcache/Optimizer/zend_cfg.h7
-rw-r--r--ext/opcache/Optimizer/zend_dfg.c4
-rw-r--r--ext/opcache/Optimizer/zend_dump.c32
-rw-r--r--ext/opcache/Optimizer/zend_func_info.c1131
-rw-r--r--ext/opcache/Optimizer/zend_func_info.h5
-rw-r--r--ext/opcache/Optimizer/zend_inference.c223
-rw-r--r--ext/opcache/Optimizer/zend_inference.h24
-rw-r--r--ext/opcache/Optimizer/zend_optimizer.c352
-rw-r--r--ext/opcache/Optimizer/zend_optimizer.h6
-rw-r--r--ext/opcache/Optimizer/zend_optimizer_internal.h3
-rw-r--r--ext/opcache/Optimizer/zend_ssa.c25
-rw-r--r--ext/opcache/Optimizer/zend_ssa.h4
25 files changed, 1720 insertions, 2332 deletions
diff --git a/ext/opcache/Optimizer/block_pass.c b/ext/opcache/Optimizer/block_pass.c
index 3327ec86df..b4cd2407ba 100644
--- a/ext/opcache/Optimizer/block_pass.c
+++ b/ext/opcache/Optimizer/block_pass.c
@@ -33,27 +33,9 @@
/* Checks if a constant (like "true") may be replaced by its value */
int zend_optimizer_get_persistent_constant(zend_string *name, zval *result, int copy)
{
- zend_constant *c;
- char *lookup_name;
- int retval = 1;
- ALLOCA_FLAG(use_heap);
-
- if ((c = zend_hash_find_ptr(EG(zend_constants), name)) == NULL) {
- lookup_name = do_alloca(ZSTR_LEN(name) + 1, use_heap);
- memcpy(lookup_name, ZSTR_VAL(name), ZSTR_LEN(name) + 1);
- zend_str_tolower(lookup_name, ZSTR_LEN(name));
-
- if ((c = zend_hash_str_find_ptr(EG(zend_constants), lookup_name, ZSTR_LEN(name))) != NULL) {
- if (!(ZEND_CONSTANT_FLAGS(c) & CONST_CT_SUBST) || (ZEND_CONSTANT_FLAGS(c) & CONST_CS)) {
- retval = 0;
- }
- } else {
- retval = 0;
- }
- free_alloca(lookup_name, use_heap);
- }
-
- if (retval) {
+ zval *zv;
+ zend_constant *c = zend_hash_find_ptr(EG(zend_constants), name);
+ if (c) {
if ((ZEND_CONSTANT_FLAGS(c) & CONST_PERSISTENT)
&& (!(ZEND_CONSTANT_FLAGS(c) & CONST_NO_FILE_CACHE)
|| !(CG(compiler_options) & ZEND_COMPILE_WITH_FILE_CACHE))) {
@@ -61,23 +43,23 @@ int zend_optimizer_get_persistent_constant(zend_string *name, zval *result, int
if (copy) {
Z_TRY_ADDREF_P(result);
}
+ return 1;
} else {
- retval = 0;
+ return 0;
}
}
- return retval;
+ /* Special constants null/true/false can always be substituted. */
+ zv = zend_get_special_const(ZSTR_VAL(name), ZSTR_LEN(name));
+ if (zv) {
+ ZVAL_COPY_VALUE(result, zv);
+ return 1;
+ }
+ return 0;
}
-/* CFG back references management */
-
-#define DEL_SOURCE(from, to)
-#define ADD_SOURCE(from, to)
-
/* Data dependencies macros */
-#define VAR_NUM_EX(op) VAR_NUM((op).var)
-
#define VAR_SOURCE(op) Tsource[VAR_NUM(op.var)]
#define SET_VAR_SOURCE(opline) Tsource[VAR_NUM(opline->result.var)] = opline
@@ -86,15 +68,6 @@ static void strip_leading_nops(zend_op_array *op_array, zend_basic_block *b)
zend_op *opcodes = op_array->opcodes;
do {
- /* check if NOP breaks incorrect smart branch */
- if (b->len == 2
- && (opcodes[b->start + 1].opcode == ZEND_JMPZ
- || opcodes[b->start + 1].opcode == ZEND_JMPNZ)
- && (opcodes[b->start + 1].op1_type & (IS_CV|IS_CONST))
- && b->start > 0
- && zend_is_smart_branch(opcodes + b->start - 1)) {
- break;
- }
b->start++;
b->len--;
} while (b->len > 0 && opcodes[b->start].opcode == ZEND_NOP);
@@ -125,14 +98,6 @@ static void strip_nops(zend_op_array *op_array, zend_basic_block *b)
}
j++;
}
- if (i + 1 < b->start + b->len
- && (op_array->opcodes[i+1].opcode == ZEND_JMPZ
- || op_array->opcodes[i+1].opcode == ZEND_JMPNZ)
- && op_array->opcodes[i+1].op1_type & (IS_CV|IS_CONST)
- && zend_is_smart_branch(op_array->opcodes + j - 1)) {
- /* don't remove NOP, that splits incorrect smart branch */
- j++;
- }
i++;
}
b->len = j - b->start;
@@ -203,52 +168,6 @@ static void zend_optimize_block(zend_basic_block *block, zend_op_array *op_array
literal_dtor(&ZEND_OP1_LITERAL(src));
MAKE_NOP(src);
++(*opt_count);
- switch (opline->opcode) {
- case ZEND_JMPZ:
- if (zend_is_true(&ZEND_OP1_LITERAL(opline))) {
- MAKE_NOP(opline);
- DEL_SOURCE(block, block->successors[0]);
- block->successors_count = 1;
- block->successors[0] = block->successors[1];
- } else {
- opline->opcode = ZEND_JMP;
- COPY_NODE(opline->op1, opline->op2);
- DEL_SOURCE(block, block->successors[1]);
- block->successors_count = 1;
- }
- break;
- case ZEND_JMPNZ:
- if (zend_is_true(&ZEND_OP1_LITERAL(opline))) {
- opline->opcode = ZEND_JMP;
- COPY_NODE(opline->op1, opline->op2);
- DEL_SOURCE(block, block->successors[1]);
- block->successors_count = 1;
- } else {
- MAKE_NOP(opline);
- DEL_SOURCE(block, block->successors[0]);
- block->successors_count = 1;
- block->successors[0] = block->successors[1];
- }
- break;
- case ZEND_JMPZNZ:
- if (zend_is_true(&ZEND_OP1_LITERAL(opline))) {
- zend_op *target_opline = ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value);
- ZEND_SET_OP_JMP_ADDR(opline, opline->op1, target_opline);
- DEL_SOURCE(block, block->successors[0]);
- block->successors[0] = block->successors[1];
- } else {
- zend_op *target_opline = ZEND_OP2_JMP_ADDR(opline);
- ZEND_SET_OP_JMP_ADDR(opline, opline->op1, target_opline);
- DEL_SOURCE(block, block->successors[0]);
- }
- block->successors_count = 1;
- opline->op1_type = IS_UNUSED;
- opline->extended_value = 0;
- opline->opcode = ZEND_JMP;
- break;
- default:
- break;
- }
} else {
zval_ptr_dtor_nogc(&c);
}
@@ -278,64 +197,55 @@ static void zend_optimize_block(zend_basic_block *block, zend_op_array *op_array
}
}
- if (opline->opcode == ZEND_ECHO) {
- if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) {
- src = VAR_SOURCE(opline->op1);
- if (src &&
- src->opcode == ZEND_CAST &&
- src->extended_value == IS_STRING) {
- /* T = CAST(X, String), ECHO(T) => NOP, ECHO(X) */
- VAR_SOURCE(opline->op1) = NULL;
- COPY_NODE(opline->op1, src->op1);
- MAKE_NOP(src);
- ++(*opt_count);
- }
- }
-
- if (opline->op1_type == IS_CONST) {
- if (last_op && last_op->opcode == ZEND_ECHO &&
- last_op->op1_type == IS_CONST &&
- Z_TYPE(ZEND_OP1_LITERAL(opline)) != IS_DOUBLE &&
- Z_TYPE(ZEND_OP1_LITERAL(last_op)) != IS_DOUBLE) {
- /* compress consecutive ECHO's.
- * Float to string conversion may be affected by current
- * locale setting.
- */
- int l, old_len;
-
- if (Z_TYPE(ZEND_OP1_LITERAL(opline)) != IS_STRING) {
- convert_to_string(&ZEND_OP1_LITERAL(opline));
- }
- if (Z_TYPE(ZEND_OP1_LITERAL(last_op)) != IS_STRING) {
- convert_to_string(&ZEND_OP1_LITERAL(last_op));
+ switch (opline->opcode) {
+ case ZEND_ECHO:
+ if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) {
+ src = VAR_SOURCE(opline->op1);
+ if (src &&
+ src->opcode == ZEND_CAST &&
+ src->extended_value == IS_STRING) {
+ /* T = CAST(X, String), ECHO(T) => NOP, ECHO(X) */
+ VAR_SOURCE(opline->op1) = NULL;
+ COPY_NODE(opline->op1, src->op1);
+ MAKE_NOP(src);
+ ++(*opt_count);
}
- old_len = Z_STRLEN(ZEND_OP1_LITERAL(last_op));
- l = old_len + Z_STRLEN(ZEND_OP1_LITERAL(opline));
- if (!Z_REFCOUNTED(ZEND_OP1_LITERAL(last_op))) {
- zend_string *tmp = zend_string_alloc(l, 0);
- memcpy(ZSTR_VAL(tmp), Z_STRVAL(ZEND_OP1_LITERAL(last_op)), old_len);
- Z_STR(ZEND_OP1_LITERAL(last_op)) = tmp;
- } else {
- Z_STR(ZEND_OP1_LITERAL(last_op)) = zend_string_extend(Z_STR(ZEND_OP1_LITERAL(last_op)), l, 0);
+ } else if (opline->op1_type == IS_CONST &&
+ Z_TYPE(ZEND_OP1_LITERAL(opline)) != IS_DOUBLE) {
+ if (last_op == opline - 1) {
+ /* compress consecutive ECHO's.
+ * Float to string conversion may be affected by current
+ * locale setting.
+ */
+ int l, old_len;
+
+ if (Z_TYPE(ZEND_OP1_LITERAL(opline)) != IS_STRING) {
+ convert_to_string(&ZEND_OP1_LITERAL(opline));
+ }
+ if (Z_TYPE(ZEND_OP1_LITERAL(last_op)) != IS_STRING) {
+ convert_to_string(&ZEND_OP1_LITERAL(last_op));
+ }
+ old_len = Z_STRLEN(ZEND_OP1_LITERAL(last_op));
+ l = old_len + Z_STRLEN(ZEND_OP1_LITERAL(opline));
+ if (!Z_REFCOUNTED(ZEND_OP1_LITERAL(last_op))) {
+ zend_string *tmp = zend_string_alloc(l, 0);
+ memcpy(ZSTR_VAL(tmp), Z_STRVAL(ZEND_OP1_LITERAL(last_op)), old_len);
+ Z_STR(ZEND_OP1_LITERAL(last_op)) = tmp;
+ } else {
+ Z_STR(ZEND_OP1_LITERAL(last_op)) = zend_string_extend(Z_STR(ZEND_OP1_LITERAL(last_op)), l, 0);
+ }
+ Z_TYPE_INFO(ZEND_OP1_LITERAL(last_op)) = IS_STRING_EX;
+ memcpy(Z_STRVAL(ZEND_OP1_LITERAL(last_op)) + old_len, Z_STRVAL(ZEND_OP1_LITERAL(opline)), Z_STRLEN(ZEND_OP1_LITERAL(opline)));
+ Z_STRVAL(ZEND_OP1_LITERAL(last_op))[l] = '\0';
+ zval_ptr_dtor_nogc(&ZEND_OP1_LITERAL(opline));
+ ZVAL_STR(&ZEND_OP1_LITERAL(opline), zend_new_interned_string(Z_STR(ZEND_OP1_LITERAL(last_op))));
+ ZVAL_NULL(&ZEND_OP1_LITERAL(last_op));
+ MAKE_NOP(last_op);
+ ++(*opt_count);
}
- Z_TYPE_INFO(ZEND_OP1_LITERAL(last_op)) = IS_STRING_EX;
- memcpy(Z_STRVAL(ZEND_OP1_LITERAL(last_op)) + old_len, Z_STRVAL(ZEND_OP1_LITERAL(opline)), Z_STRLEN(ZEND_OP1_LITERAL(opline)));
- Z_STRVAL(ZEND_OP1_LITERAL(last_op))[l] = '\0';
- zval_ptr_dtor_nogc(&ZEND_OP1_LITERAL(opline));
- ZVAL_STR(&ZEND_OP1_LITERAL(opline), zend_new_interned_string(Z_STR(ZEND_OP1_LITERAL(last_op))));
- ZVAL_NULL(&ZEND_OP1_LITERAL(last_op));
- MAKE_NOP(last_op);
- ++(*opt_count);
+ last_op = opline;
}
- last_op = opline;
- } else {
- last_op = NULL;
- }
- } else {
- last_op = NULL;
- }
-
- switch (opline->opcode) {
+ break;
case ZEND_FREE:
if (opline->op1_type == IS_TMP_VAR) {
@@ -592,6 +502,7 @@ static void zend_optimize_block(zend_basic_block *block, zend_op_array *op_array
MAKE_NOP(opline);
++(*opt_count);
break;
+ case ZEND_ISSET_ISEMPTY_CV:
case ZEND_ISSET_ISEMPTY_VAR:
case ZEND_ISSET_ISEMPTY_DIM_OBJ:
case ZEND_ISSET_ISEMPTY_PROP_OBJ:
@@ -600,6 +511,7 @@ static void zend_optimize_block(zend_basic_block *block, zend_op_array *op_array
case ZEND_TYPE_CHECK:
case ZEND_DEFINED:
case ZEND_IN_ARRAY:
+ case ZEND_ARRAY_KEY_EXISTS:
if (opline->opcode == ZEND_BOOL_NOT) {
break;
}
@@ -615,56 +527,135 @@ static void zend_optimize_block(zend_basic_block *block, zend_op_array *op_array
case ZEND_JMPZ:
case ZEND_JMPNZ:
- case ZEND_JMPZ_EX:
- case ZEND_JMPNZ_EX:
- case ZEND_JMPZNZ:
- optimize_jmpznz:
- if (opline->op1_type == IS_TMP_VAR &&
- (!zend_bitset_in(used_ext, VAR_NUM(opline->op1.var)) ||
- (opline->result_type == opline->op1_type &&
- opline->result.var == opline->op1.var))) {
- src = VAR_SOURCE(opline->op1);
- if (src) {
- if (src->opcode == ZEND_BOOL_NOT &&
- opline->opcode != ZEND_JMPZ_EX &&
- opline->opcode != ZEND_JMPNZ_EX) {
- VAR_SOURCE(opline->op1) = NULL;
- COPY_NODE(opline->op1, src->op1);
- if (opline->opcode == ZEND_JMPZ) {
+ while (1) {
+ if (opline->op1_type == IS_CONST) {
+ ++(*opt_count);
+ block->successors_count = 1;
+ if (zend_is_true(&ZEND_OP1_LITERAL(opline)) ==
+ (opline->opcode == ZEND_JMPZ)) {
+
+ MAKE_NOP(opline);
+ block->successors[0] = block->successors[1];
+ block->len--;
+ cfg->blocks[block->successors[0]].flags |= ZEND_BB_FOLLOW;
+ break;
+ } else {
+ zend_basic_block *next = cfg->blocks + block->successors[1];
+
+ next->flags &= ~ZEND_BB_FOLLOW;
+ if (!(next->flags & (ZEND_BB_TARGET|ZEND_BB_PROTECTED))) {
+ next->flags &= ~ZEND_BB_REACHABLE;
+ }
+ opline->opcode = ZEND_JMP;
+ COPY_NODE(opline->op1, opline->op2);
+ break;
+ }
+ } else if (opline->op1_type == IS_TMP_VAR &&
+ !zend_bitset_in(used_ext, VAR_NUM(opline->op1.var))) {
+ src = VAR_SOURCE(opline->op1);
+ if (src) {
+ if (src->opcode == ZEND_BOOL_NOT) {
+ VAR_SOURCE(opline->op1) = NULL;
+ COPY_NODE(opline->op1, src->op1);
/* T = BOOL_NOT(X) + JMPZ(T) -> NOP, JMPNZ(X) */
- opline->opcode = ZEND_JMPNZ;
- } else if (opline->opcode == ZEND_JMPNZ) {
- /* T = BOOL_NOT(X) + JMPNZ(T) -> NOP, JMPZ(X) */
- opline->opcode = ZEND_JMPZ;
-#if 0
- } else if (opline->opcode == ZEND_JMPZ_EX) {
- /* T = BOOL_NOT(X) + JMPZ_EX(T) -> NOP, JMPNZ_EX(X) */
- opline->opcode = ZEND_JMPNZ_EX;
- } else if (opline->opcode == ZEND_JMPNZ_EX) {
- /* T = BOOL_NOT(X) + JMPNZ_EX(T) -> NOP, JMPZ_EX(X) */
- opline->opcode = ZEND_JMPZ;
-#endif
- } else {
+ opline->opcode = INV_COND(opline->opcode);
+ MAKE_NOP(src);
+ ++(*opt_count);
+ continue;
+ } else if (src->opcode == ZEND_BOOL ||
+ src->opcode == ZEND_QM_ASSIGN) {
+ VAR_SOURCE(opline->op1) = NULL;
+ COPY_NODE(opline->op1, src->op1);
+ MAKE_NOP(src);
+ ++(*opt_count);
+ continue;
+ }
+ }
+ }
+ break;
+ }
+ break;
+
+ case ZEND_JMPZNZ:
+ while (1) {
+ if (opline->op1_type == IS_CONST) {
+ ++(*opt_count);
+ if (zend_is_true(&ZEND_OP1_LITERAL(opline))) {
+ zend_op *target_opline = ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value);
+ ZEND_SET_OP_JMP_ADDR(opline, opline->op1, target_opline);
+ block->successors[0] = block->successors[1];
+ } else {
+ zend_op *target_opline = ZEND_OP2_JMP_ADDR(opline);
+ ZEND_SET_OP_JMP_ADDR(opline, opline->op1, target_opline);
+ }
+ block->successors_count = 1;
+ opline->op1_type = IS_UNUSED;
+ opline->extended_value = 0;
+ opline->opcode = ZEND_JMP;
+ break;
+ } else if (opline->op1_type == IS_TMP_VAR &&
+ !zend_bitset_in(used_ext, VAR_NUM(opline->op1.var))) {
+ src = VAR_SOURCE(opline->op1);
+ if (src) {
+ if (src->opcode == ZEND_BOOL_NOT) {
/* T = BOOL_NOT(X) + JMPZNZ(T,L1,L2) -> NOP, JMPZNZ(X,L2,L1) */
uint32_t tmp;
- ZEND_ASSERT(opline->opcode == ZEND_JMPZNZ);
+ VAR_SOURCE(opline->op1) = NULL;
+ COPY_NODE(opline->op1, src->op1);
tmp = block->successors[0];
block->successors[0] = block->successors[1];
block->successors[1] = tmp;
+ MAKE_NOP(src);
+ ++(*opt_count);
+ continue;
+ } else if (src->opcode == ZEND_BOOL ||
+ src->opcode == ZEND_QM_ASSIGN) {
+ VAR_SOURCE(opline->op1) = NULL;
+ COPY_NODE(opline->op1, src->op1);
+ MAKE_NOP(src);
+ ++(*opt_count);
+ continue;
}
- MAKE_NOP(src);
- ++(*opt_count);
- goto optimize_jmpznz;
- } else if (src->opcode == ZEND_BOOL ||
- src->opcode == ZEND_QM_ASSIGN) {
- VAR_SOURCE(opline->op1) = NULL;
- COPY_NODE(opline->op1, src->op1);
- MAKE_NOP(src);
+ }
+ }
+ break;
+ }
+ break;
+
+ case ZEND_JMPZ_EX:
+ case ZEND_JMPNZ_EX:
+ while (1) {
+ if (opline->op1_type == IS_CONST) {
+ if (zend_is_true(&ZEND_OP1_LITERAL(opline)) ==
+ (opline->opcode == ZEND_JMPZ_EX)) {
+
++(*opt_count);
- goto optimize_jmpznz;
+ opline->opcode = ZEND_QM_ASSIGN;
+ zval_ptr_dtor_nogc(&ZEND_OP1_LITERAL(opline));
+ ZVAL_BOOL(&ZEND_OP1_LITERAL(opline), opline->opcode == ZEND_JMPZ_EX);
+ opline->op2.num = 0;
+ block->successors_count = 1;
+ block->successors[0] = block->successors[1];
+ cfg->blocks[block->successors[0]].flags |= ZEND_BB_FOLLOW;
+ break;
+ }
+ } else if (opline->op1_type == IS_TMP_VAR &&
+ (!zend_bitset_in(used_ext, VAR_NUM(opline->op1.var)) ||
+ opline->result.var == opline->op1.var)) {
+ src = VAR_SOURCE(opline->op1);
+ if (src) {
+ if (src->opcode == ZEND_BOOL ||
+ src->opcode == ZEND_QM_ASSIGN) {
+ VAR_SOURCE(opline->op1) = NULL;
+ COPY_NODE(opline->op1, src->op1);
+ MAKE_NOP(src);
+ ++(*opt_count);
+ continue;
+ }
}
}
+ break;
}
break;
@@ -894,6 +885,23 @@ optimize_const_unary_op:
/* strip T = QM_ASSIGN(T) */
MAKE_NOP(opline);
++(*opt_count);
+ } else if (opline->op1_type == IS_TMP_VAR &&
+ opline->result_type == IS_TMP_VAR &&
+ !zend_bitset_in(used_ext, VAR_NUM(opline->op1.var))) {
+ /* T1 = ..., T2 = QM_ASSIGN(T1) to T2 = ..., NOP */
+ src = VAR_SOURCE(opline->op1);
+ if (src &&
+ src->opcode != ZEND_COPY_TMP &&
+ src->opcode != ZEND_ADD_ARRAY_ELEMENT &&
+ src->opcode != ZEND_ADD_ARRAY_UNPACK &&
+ (src->opcode != ZEND_DECLARE_LAMBDA_FUNCTION ||
+ src == opline -1)) {
+ src->result.var = opline->result.var;
+ VAR_SOURCE(opline->op1) = NULL;
+ VAR_SOURCE(opline->result) = src;
+ MAKE_NOP(opline);
+ ++(*opt_count);
+ }
}
break;
}
@@ -1089,11 +1097,84 @@ static void assemble_code_blocks(zend_cfg *cfg, zend_op_array *op_array, zend_op
}
}
-static void zend_jmp_optimization(zend_basic_block *block, zend_op_array *op_array, zend_cfg *cfg, zend_uchar *same_t, uint32_t *opt_count)
+static zend_always_inline zend_basic_block *get_target_block(const zend_cfg *cfg, zend_basic_block *block, int n, uint32_t *opt_count)
+{
+ int b;
+ zend_basic_block *target_block = cfg->blocks + block->successors[n];
+
+ if (target_block->len == 0 && !(target_block->flags & ZEND_BB_PROTECTED)) {
+ do {
+ b = target_block->successors[0];
+ target_block = cfg->blocks + b;
+ } while (target_block->len == 0 && !(target_block->flags & ZEND_BB_PROTECTED));
+ block->successors[n] = b;
+ ++(*opt_count);
+ }
+ return target_block;
+}
+
+static zend_always_inline zend_basic_block *get_follow_block(const zend_cfg *cfg, zend_basic_block *block, int n, uint32_t *opt_count)
+{
+ int b;
+ zend_basic_block *target_block = cfg->blocks + block->successors[n];
+
+ if (target_block->len == 0 && !(target_block->flags & ZEND_BB_PROTECTED)) {
+ do {
+ b = target_block->successors[0];
+ target_block = cfg->blocks + b;
+ } while (target_block->len == 0 && !(target_block->flags & ZEND_BB_PROTECTED));
+ block->successors[n] = b;
+ ++(*opt_count);
+ }
+ return target_block;
+}
+
+static zend_always_inline zend_basic_block *get_next_block(const zend_cfg *cfg, zend_basic_block *block)
+{
+ zend_basic_block *next_block = block + 1;
+ zend_basic_block *end = cfg->blocks + cfg->blocks_count;
+
+ while (1) {
+ if (next_block == end) {
+ return NULL;
+ } else if (next_block->flags & ZEND_BB_REACHABLE) {
+ break;
+ }
+ next_block++;
+ }
+ while (next_block->len == 0 && !(next_block->flags & ZEND_BB_PROTECTED)) {
+ next_block = cfg->blocks + next_block->successors[0];
+ }
+ return next_block;
+}
+
+
+/* we use "jmp_hitlist" to avoid infinity loops during jmp optimization */
+static zend_always_inline int in_hitlist(int target, int *jmp_hitlist, int jmp_hitlist_count)
+{
+ int i;
+
+ for (i = 0; i < jmp_hitlist_count; i++) {
+ if (jmp_hitlist[i] == target) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+#define CHECK_LOOP(target) \
+ if (EXPECTED(!in_hitlist(target, jmp_hitlist, jmp_hitlist_count))) { \
+ jmp_hitlist[jmp_hitlist_count++] = target; \
+ } else { \
+ break; \
+ }
+
+static void zend_jmp_optimization(zend_basic_block *block, zend_op_array *op_array, const zend_cfg *cfg, int *jmp_hitlist, uint32_t *opt_count)
{
/* last_op is the last opcode of the current block */
- zend_basic_block *blocks = cfg->blocks;
- zend_op *last_op;
+ zend_basic_block *target_block, *follow_block, *next_block;
+ zend_op *last_op, *target;
+ int next, jmp_hitlist_count;
if (block->len == 0) {
return;
@@ -1102,35 +1183,32 @@ static void zend_jmp_optimization(zend_basic_block *block, zend_op_array *op_arr
last_op = op_array->opcodes + block->start + block->len - 1;
switch (last_op->opcode) {
case ZEND_JMP:
- {
- zend_basic_block *target_block = blocks + block->successors[0];
- zend_op *target = op_array->opcodes + target_block->start;
- int next = (block - blocks) + 1;
-
- while (next < cfg->blocks_count && !(blocks[next].flags & ZEND_BB_REACHABLE)) {
- /* find used one */
- next++;
- }
+ jmp_hitlist_count = 0;
- /* JMP(next) -> NOP */
- if (block->successors[0] == next) {
- MAKE_NOP(last_op);
- ++(*opt_count);
- block->len--;
+ target_block = get_target_block(cfg, block, 0, opt_count);
+ while (target_block->len == 1) {
+ target = op_array->opcodes + target_block->start;
+ if (target->opcode == ZEND_JMP) {
+ /* JMP L, L: JMP L1 -> JMP L1 */
+ next = target_block->successors[0];
+ } else {
break;
}
+ CHECK_LOOP(next);
+ block->successors[0] = next;
+ ++(*opt_count);
+ target_block = get_target_block(cfg, block, 0, opt_count);
+ }
- if (target->opcode == ZEND_JMP &&
- block->successors[0] != target_block->successors[0] &&
- !(target_block->flags & ZEND_BB_PROTECTED)) {
- /* JMP L, L: JMP L1 -> JMP L1 */
- *last_op = *target;
- DEL_SOURCE(block, block->successors[0]);
- block->successors[0] = target_block->successors[0];
- ADD_SOURCE(block, block->successors[0]);
- ++(*opt_count);
- } else if (target->opcode == ZEND_JMPZNZ &&
- !(target_block->flags & ZEND_BB_PROTECTED)) {
+ next_block = get_next_block(cfg, block);
+ if (target_block == next_block) {
+ /* JMP(next) -> NOP */
+ MAKE_NOP(last_op);
+ ++(*opt_count);
+ block->len--;
+ } else if (target_block->len == 1) {
+ target = op_array->opcodes + target_block->start;
+ if (target->opcode == ZEND_JMPZNZ) {
/* JMP L, L: JMPZNZ L1,L2 -> JMPZNZ L1,L2 */
*last_op = *target;
if (last_op->op1_type == IS_CONST) {
@@ -1138,15 +1216,14 @@ static void zend_jmp_optimization(zend_basic_block *block, zend_op_array *op_arr
ZVAL_COPY(&zv, &ZEND_OP1_LITERAL(last_op));
last_op->op1.constant = zend_optimizer_add_literal(op_array, &zv);
}
- DEL_SOURCE(block, block->successors[0]);
block->successors_count = 2;
block->successors[0] = target_block->successors[0];
block->successors[1] = target_block->successors[1];
- ADD_SOURCE(block, block->successors[0]);
- ADD_SOURCE(block, block->successors[1]);
++(*opt_count);
+ goto optimize_jmpznz;
} else if ((target->opcode == ZEND_RETURN ||
target->opcode == ZEND_RETURN_BY_REF ||
+ target->opcode == ZEND_GENERATOR_RETURN ||
target->opcode == ZEND_EXIT) &&
!(op_array->fn_flags & ZEND_ACC_HAS_FINALLY_BLOCK)) {
/* JMP L, L: RETURN to immediate RETURN */
@@ -1156,96 +1233,68 @@ static void zend_jmp_optimization(zend_basic_block *block, zend_op_array *op_arr
ZVAL_COPY(&zv, &ZEND_OP1_LITERAL(last_op));
last_op->op1.constant = zend_optimizer_add_literal(op_array, &zv);
}
- DEL_SOURCE(block, block->successors[0]);
block->successors_count = 0;
++(*opt_count);
-#if 0
- /* Temporarily disabled - see bug #0025274 */
- } else if (0&& block->op1_to != block &&
- block->op1_to != blocks &&
- op_array->last_try_catch == 0 &&
- target->opcode != ZEND_FREE) {
- /* Block Reordering (saves one JMP on each "for" loop iteration)
- * It is disabled for some cases (ZEND_FREE)
- * which may break register allocation.
- */
- zend_bool can_reorder = 0;
- zend_block_source *cs = block->op1_to->sources;
-
- /* the "target" block doesn't had any followed block */
- while(cs) {
- if (cs->from->follow_to == block->op1_to) {
- can_reorder = 0;
- break;
- }
- cs = cs->next;
- }
- if (can_reorder) {
- next = block->op1_to;
- /* the "target" block is not followed by current "block" */
- while (next->follow_to != NULL) {
- if (next->follow_to == block) {
- can_reorder = 0;
- break;
- }
- next = next->follow_to;
- }
- if (can_reorder) {
- zend_basic_block *prev = blocks;
+ }
+ }
+ break;
- while (prev->next != block->op1_to) {
- prev = prev->next;
- }
- prev->next = next->next;
- next->next = block->next;
- block->next = block->op1_to;
+ case ZEND_JMP_SET:
+ case ZEND_COALESCE:
+ jmp_hitlist_count = 0;
- block->follow_to = block->op1_to;
- block->op1_to = NULL;
- MAKE_NOP(last_op);
- block->len--;
- if(block->len == 0) {
- /* this block is nothing but NOP now */
- delete_code_block(block, ctx);
- }
- break;
- }
- }
-#endif
+ target_block = get_target_block(cfg, block, 0, opt_count);
+ while (target_block->len == 1) {
+ target = op_array->opcodes + target_block->start;
+
+ if (target->opcode == ZEND_JMP) {
+ /* JMP_SET(X, L), L: JMP(L2) -> JMP_SET(X, L2) */
+ next = target_block->successors[0];
+ CHECK_LOOP(next);
+ block->successors[0] = next;
+ ++(*opt_count);
+ } else {
+ break;
}
+ target_block = get_target_block(cfg, block, 0, opt_count);
}
break;
case ZEND_JMPZ:
case ZEND_JMPNZ:
- /* constant conditional JMPs */
- if (last_op->op1_type == IS_CONST) {
- int should_jmp = zend_is_true(&ZEND_OP1_LITERAL(last_op));
+ jmp_hitlist_count = 0;
- if (last_op->opcode == ZEND_JMPZ) {
- should_jmp = !should_jmp;
- }
- literal_dtor(&ZEND_OP1_LITERAL(last_op));
- last_op->op1_type = IS_UNUSED;
- if (should_jmp) {
- /* JMPNZ(true) -> JMP */
- last_op->opcode = ZEND_JMP;
- DEL_SOURCE(block, block->successors[1]);
- block->successors_count = 1;
+ target_block = get_target_block(cfg, block, 0, opt_count);
+ while (target_block->len == 1) {
+ target = op_array->opcodes + target_block->start;
+
+ if (target->opcode == ZEND_JMP) {
+ /* JMPZ(X, L), L: JMP(L2) -> JMPZ(X, L2) */
+ next = target_block->successors[0];
+ } else if (target->opcode == last_op->opcode &&
+ SAME_VAR(target->op1, last_op->op1)) {
+ /* JMPZ(X, L), L: JMPZ(X, L2) -> JMPZ(X, L2) */
+ next = target_block->successors[0];
+ } else if (target->opcode == INV_COND(last_op->opcode) &&
+ SAME_VAR(target->op1, last_op->op1)) {
+ /* JMPZ(X, L), L: JMPNZ(X, L2) -> JMPZ(X, L+1) */
+ next = target_block->successors[1];
+ } else if (target->opcode == ZEND_JMPZNZ &&
+ SAME_VAR(target->op1, last_op->op1)) {
+ /* JMPZ(X, L), L: JMPZNZ(X, L2, L3) -> JMPZ(X, L2) */
+ next = target_block->successors[last_op->opcode == ZEND_JMPNZ];
} else {
- /* JMPNZ(false) -> NOP */
- MAKE_NOP(last_op);
- DEL_SOURCE(block, block->successors[0]);
- block->successors_count = 1;
- block->successors[0] = block->successors[1];
+ break;
}
+ CHECK_LOOP(next);
+ block->successors[0] = next;
++(*opt_count);
- break;
+ target_block = get_target_block(cfg, block, 0, opt_count);
}
- if (block->successors[0] == block->successors[1]) {
+ follow_block = get_follow_block(cfg, block, 1, opt_count);
+ if (target_block == follow_block) {
/* L: JMP[N]Z(X, L+1) -> NOP or FREE(X) */
-
if (last_op->op1_type == IS_CV) {
last_op->opcode = ZEND_CHECK_VAR;
last_op->op2.num = 0;
@@ -1254,122 +1303,55 @@ static void zend_jmp_optimization(zend_basic_block *block, zend_op_array *op_arr
last_op->op2.num = 0;
} else {
MAKE_NOP(last_op);
+ block->len--;
}
block->successors_count = 1;
++(*opt_count);
- break;
- }
+ } else if (follow_block->len == 1) {
+ target = op_array->opcodes + follow_block->start;
+ if (target->opcode == ZEND_JMP) {
+ if (block->successors[0] == follow_block->successors[0]) {
+ /* JMPZ(X,L1), JMP(L1) -> NOP, JMP(L1) */
+ if (last_op->op1_type == IS_CV) {
+ last_op->opcode = ZEND_CHECK_VAR;
+ last_op->op2.num = 0;
+ } else if (last_op->op1_type & (IS_VAR|IS_TMP_VAR)) {
+ last_op->opcode = ZEND_FREE;
+ last_op->op2.num = 0;
+ } else {
+ MAKE_NOP(last_op);
+ block->len--;
+ }
+ block->successors_count = 1;
+ ++(*opt_count);
+ break;
+ } else if (!(follow_block->flags & (ZEND_BB_TARGET | ZEND_BB_PROTECTED))) {
+ next_block = get_next_block(cfg, follow_block);
- if (1) {
- zend_uchar same_type = last_op->op1_type;
- uint32_t same_var = VAR_NUM_EX(last_op->op1);
- zend_op *target;
- zend_op *target_end;
- zend_basic_block *target_block = blocks + block->successors[0];
+ if (target_block == next_block) {
+ /* JMPZ(X,L1) JMP(L2) L1: -> JMPNZ(X,L2) NOP*/
-next_target:
- target = op_array->opcodes + target_block->start;
- target_end = target + target_block->len;
- while (target < target_end && target->opcode == ZEND_NOP) {
- target++;
- }
+ last_op->opcode = INV_COND(last_op->opcode);
- /* next block is only NOP's */
- if (target == target_end) {
- target_block = blocks + target_block->successors[0];
- ++(*opt_count);
- goto next_target;
- } else if (target->opcode == INV_COND(last_op->opcode) &&
- /* JMPZ(X, L), L: JMPNZ(X, L2) -> JMPZ(X, L+1) */
- (target->op1_type & (IS_TMP_VAR|IS_CV)) &&
- same_type == target->op1_type &&
- same_var == VAR_NUM_EX(target->op1) &&
- !(target_block->flags & ZEND_BB_PROTECTED)
- ) {
- DEL_SOURCE(block, block->successors[0]);
- block->successors[0] = target_block->successors[1];
- ADD_SOURCE(block, block->successors[0]);
- ++(*opt_count);
- } else if (target->opcode == INV_COND_EX(last_op->opcode) &&
- (target->op1_type & (IS_TMP_VAR|IS_CV)) &&
- same_type == target->op1_type &&
- same_var == VAR_NUM_EX(target->op1) &&
- !(target_block->flags & ZEND_BB_PROTECTED)) {
- /* JMPZ(X, L), L: T = JMPNZ_EX(X, L2) -> T = JMPZ_EX(X, L+1) */
- last_op->opcode += 3;
- COPY_NODE(last_op->result, target->result);
- DEL_SOURCE(block, block->successors[0]);
- block->successors[0] = target_block->successors[1];
- ADD_SOURCE(block, block->successors[0]);
- ++(*opt_count);
- } else if (target->opcode == last_op->opcode &&
- (target->op1_type & (IS_TMP_VAR|IS_CV)) &&
- same_type == target->op1_type &&
- same_var == VAR_NUM_EX(target->op1) &&
- !(target_block->flags & ZEND_BB_PROTECTED)) {
- /* JMPZ(X, L), L: JMPZ(X, L2) -> JMPZ(X, L2) */
- DEL_SOURCE(block, block->successors[0]);
- block->successors[0] = target_block->successors[0];
- ADD_SOURCE(block, block->successors[0]);
- ++(*opt_count);
- } else if (target->opcode == ZEND_JMP &&
- !(target_block->flags & ZEND_BB_PROTECTED)) {
- /* JMPZ(X, L), L: JMP(L2) -> JMPZ(X, L2) */
- DEL_SOURCE(block, block->successors[0]);
- block->successors[0] = target_block->successors[0];
- ADD_SOURCE(block, block->successors[0]);
- ++(*opt_count);
- } else if (target->opcode == ZEND_JMPZNZ &&
- (target->op1_type & (IS_TMP_VAR|IS_CV)) &&
- same_type == target->op1_type &&
- same_var == VAR_NUM_EX(target->op1) &&
- !(target_block->flags & ZEND_BB_PROTECTED)) {
- /* JMPZ(X, L), L: JMPZNZ(X, L2, L3) -> JMPZ(X, L2) */
- DEL_SOURCE(block, block->successors[0]);
- if (last_op->opcode == ZEND_JMPZ) {
- block->successors[0] = target_block->successors[0];
- } else {
- block->successors[0] = target_block->successors[1];
- }
- ADD_SOURCE(block, block->successors[0]);
- ++(*opt_count);
- }
- }
+ block->successors[0] = follow_block->successors[0];
+ block->successors[1] = next_block - cfg->blocks;
- if (last_op->opcode == ZEND_JMPZ || last_op->opcode == ZEND_JMPNZ) {
- zend_op *target;
- zend_op *target_end;
- zend_basic_block *target_block;
+ follow_block->flags &= ~ZEND_BB_REACHABLE;
+ MAKE_NOP(target);
+ follow_block->len = 0;
- while (1) {
- target_block = blocks + block->successors[1];
- target = op_array->opcodes + target_block->start;
- target_end = op_array->opcodes + target_block->start + 1;
- while (target < target_end && target->opcode == ZEND_NOP) {
- target++;
- }
+ next_block->flags |= ZEND_BB_FOLLOW;
- /* next block is only NOP's */
- if (target == target_end && !(target_block->flags & ZEND_BB_PROTECTED)) {
- DEL_SOURCE(block, block->successors[1]);
- block->successors[1] = target_block->successors[0];
- ADD_SOURCE(block, block->successors[1]);
- ++(*opt_count);
- } else {
- break;
+ break;
+ }
}
- }
- /* JMPZ(X,L1), JMP(L2) -> JMPZNZ(X,L1,L2) */
- if (target->opcode == ZEND_JMP &&
- !(target_block->flags & ZEND_BB_PROTECTED)) {
- DEL_SOURCE(block, block->successors[1]);
+
+ /* JMPZ(X,L1), JMP(L2) -> JMPZNZ(X,L1,L2) */
if (last_op->opcode == ZEND_JMPZ) {
- block->successors[1] = target_block->successors[0];
- ADD_SOURCE(block, block->successors[1]);
+ block->successors[1] = follow_block->successors[0];
} else {
block->successors[1] = block->successors[0];
- block->successors[0] = target_block->successors[0];
- ADD_SOURCE(block, block->successors[0]);
+ block->successors[0] = follow_block->successors[0];
}
last_op->opcode = ZEND_JMPZNZ;
++(*opt_count);
@@ -1379,212 +1361,153 @@ next_target:
case ZEND_JMPNZ_EX:
case ZEND_JMPZ_EX:
- /* constant conditional JMPs */
- if (last_op->op1_type == IS_CONST) {
- int should_jmp = zend_is_true(&ZEND_OP1_LITERAL(last_op));
-
- if (last_op->opcode == ZEND_JMPZ_EX) {
- should_jmp = !should_jmp;
- }
- if (!should_jmp) {
- /* T = JMPZ_EX(true,L) -> T = QM_ASSIGN(true)
- * T = JMPNZ_EX(false,L) -> T = QM_ASSIGN(false)
- */
- last_op->opcode = ZEND_QM_ASSIGN;
- SET_UNUSED(last_op->op2);
- DEL_SOURCE(block, block->successors[0]);
- block->successors_count = 1;
- block->successors[0] = block->successors[1];
- ++(*opt_count);
- }
- break;
- }
-
- if (1) {
- zend_op *target, *target_end;
- zend_basic_block *target_block;
- int var_num = op_array->last_var + op_array->T;
+ jmp_hitlist_count = 0;
- if (var_num <= 0) {
- return;
- }
- memset(same_t, 0, var_num);
- same_t[VAR_NUM_EX(last_op->op1)] |= last_op->op1_type;
- same_t[VAR_NUM_EX(last_op->result)] |= last_op->result_type;
- target_block = blocks + block->successors[0];
-next_target_ex:
+ target_block = get_target_block(cfg, block, 0, opt_count);
+ while (target_block->len == 1) {
target = op_array->opcodes + target_block->start;
- target_end = target + target_block->len;
- while (target < target_end && target->opcode == ZEND_NOP) {
- target++;
- }
- /* next block is only NOP's */
- if (target == target_end) {
- target_block = blocks + target_block->successors[0];
- ++(*opt_count);
- goto next_target_ex;
+
+ if (target->opcode == ZEND_JMP) {
+ /* T = JMPZ_EX(X, L), L: JMP(L2) -> T = JMPZ(X, L2) */
+ next = target_block->successors[0];
} else if (target->opcode == last_op->opcode-3 &&
- (target->op1_type & (IS_TMP_VAR|IS_CV)) &&
- (same_t[VAR_NUM_EX(target->op1)] & target->op1_type) != 0 &&
- !(target_block->flags & ZEND_BB_PROTECTED)) {
+ (SAME_VAR(target->op1, last_op->result) ||
+ SAME_VAR(target->op1, last_op->op1))) {
/* T = JMPZ_EX(X, L1), L1: JMPZ({X|T}, L2) -> T = JMPZ_EX(X, L2) */
- DEL_SOURCE(block, block->successors[0]);
- block->successors[0] = target_block->successors[0];
- ADD_SOURCE(block, block->successors[0]);
- ++(*opt_count);
- } else if (target->opcode == INV_EX_COND(last_op->opcode) &&
- (target->op1_type & (IS_TMP_VAR|IS_CV)) &&
- (same_t[VAR_NUM_EX(target->op1)] & target->op1_type) != 0 &&
- !(target_block->flags & ZEND_BB_PROTECTED)) {
- /* T = JMPZ_EX(X, L1), L1: JMPNZ({X|T1}, L2) -> T = JMPZ_EX(X, L1+1) */
- DEL_SOURCE(block, block->successors[0]);
- block->successors[0] = target_block->successors[1];
- ADD_SOURCE(block, block->successors[0]);
- ++(*opt_count);
- } else if (target->opcode == INV_EX_COND_EX(last_op->opcode) &&
- (target->op1_type & (IS_TMP_VAR|IS_CV)) &&
- (same_t[VAR_NUM_EX(target->op1)] & target->op1_type) != 0 &&
- (same_t[VAR_NUM_EX(target->result)] & target->result_type) != 0 &&
- !(target_block->flags & ZEND_BB_PROTECTED)) {
- /* T = JMPZ_EX(X, L1), L1: T = JMPNZ_EX(T, L2) -> T = JMPZ_EX(X, L1+1) */
- DEL_SOURCE(block, block->successors[0]);
- block->successors[0] = target_block->successors[1];
- ADD_SOURCE(block, block->successors[0]);
- ++(*opt_count);
+ next = target_block->successors[0];
} else if (target->opcode == last_op->opcode &&
- (target->op1_type & (IS_TMP_VAR|IS_CV)) &&
- (same_t[VAR_NUM_EX(target->op1)] & target->op1_type) != 0 &&
- (same_t[VAR_NUM_EX(target->result)] & target->result_type) != 0 &&
- !(target_block->flags & ZEND_BB_PROTECTED)) {
- /* T = JMPZ_EX(X, L1), L1: T = JMPZ({X|T}, L2) -> T = JMPZ_EX(X, L2) */
- DEL_SOURCE(block, block->successors[0]);
- block->successors[0] = target_block->successors[0];
- ADD_SOURCE(block, block->successors[0]);
- ++(*opt_count);
- } else if (target->opcode == ZEND_JMP &&
- !(target_block->flags & ZEND_BB_PROTECTED)) {
- /* T = JMPZ_EX(X, L), L: JMP(L2) -> T = JMPZ(X, L2) */
- DEL_SOURCE(block, block->successors[0]);
- block->successors[0] = target_block->successors[0];
- ADD_SOURCE(block, block->successors[0]);
- ++(*opt_count);
+ target->result.var == last_op->result.var &&
+ (SAME_VAR(target->op1, last_op->result) ||
+ SAME_VAR(target->op1, last_op->op1))) {
+ /* T = JMPZ_EX(X, L1), L1: T = JMPZ_EX({X|T}, L2) -> T = JMPZ_EX(X, L2) */
+ next = target_block->successors[0];
} else if (target->opcode == ZEND_JMPZNZ &&
- (target->op1_type & (IS_TMP_VAR|IS_CV)) &&
- (same_t[VAR_NUM_EX(target->op1)] & target->op1_type) != 0 &&
- !(target_block->flags & ZEND_BB_PROTECTED)) {
+ (SAME_VAR(target->op1, last_op->result) ||
+ SAME_VAR(target->op1, last_op->op1))) {
/* T = JMPZ_EX(X, L), L: JMPZNZ({X|T}, L2, L3) -> T = JMPZ_EX(X, L2) */
- DEL_SOURCE(block, block->successors[0]);
- if (last_op->opcode == ZEND_JMPZ_EX) {
- block->successors[0] = target_block->successors[0];
- } else {
- block->successors[0] = target_block->successors[1];
- }
- ADD_SOURCE(block, block->successors[0]);
- ++(*opt_count);
+ next = target_block->successors[last_op->opcode == ZEND_JMPNZ_EX];
+ } else if (target->opcode == INV_EX_COND(last_op->opcode) &&
+ (SAME_VAR(target->op1, last_op->result) ||
+ SAME_VAR(target->op1, last_op->op1))) {
+ /* T = JMPZ_EX(X, L1), L1: JMPNZ({X|T1}, L2) -> T = JMPZ_EX(X, L1+1) */
+ next = target_block->successors[1];
+ } else if (target->opcode == INV_EX_COND_EX(last_op->opcode) &&
+ target->result.var == last_op->result.var &&
+ (SAME_VAR(target->op1, last_op->result) ||
+ SAME_VAR(target->op1, last_op->op1))) {
+ /* T = JMPZ_EX(X, L1), L1: T = JMPNZ_EX({X|T}, L2) -> T = JMPZ_EX(X, L1+1) */
+ next = target_block->successors[1];
+ } else if (target->opcode == ZEND_BOOL &&
+ (SAME_VAR(target->op1, last_op->result) ||
+ SAME_VAR(target->op1, last_op->op1))) {
+ /* convert Y = JMPZ_EX(X,L1), L1: Z = BOOL(Y) to
+ Z = JMPZ_EX(X,L1+1) */
+
+ /* NOTE: This optimization pattern is not safe, but works, */
+ /* because result of JMPZ_EX instruction */
+ /* is not used on the following path and */
+ /* should be used once on the branch path. */
+ /* */
+ /* The pattern works well only if jums processed in */
+ /* direct order, otherwise it breakes JMPZ_EX */
+ /* sequences too early. */
+ last_op->result.var = target->result.var;
+ next = target_block->successors[0];
+ } else {
+ break;
}
+ CHECK_LOOP(next);
+ block->successors[0] = next;
+ ++(*opt_count);
+ target_block = get_target_block(cfg, block, 0, opt_count);
+ }
+
+ follow_block = get_follow_block(cfg, block, 1, opt_count);
+ if (target_block == follow_block) {
+ /* L: T = JMP[N]Z_EX(X, L+1) -> T = BOOL(X) */
+ last_op->opcode = ZEND_BOOL;
+ last_op->op2.num = 0;
+ block->successors_count = 1;
+ ++(*opt_count);
+ break;
}
break;
case ZEND_JMPZNZ: {
- int next = (block - blocks) + 1;
+optimize_jmpznz:
+ jmp_hitlist_count = 0;
+ target_block = get_target_block(cfg, block, 0, opt_count);
+ while (target_block->len == 1) {
+ target = op_array->opcodes + target_block->start;
- while (next < cfg->blocks_count && !(blocks[next].flags & ZEND_BB_REACHABLE)) {
- /* find first accessed one */
- next++;
+ if (target->opcode == ZEND_JMP) {
+ /* JMPZNZ(X, L1, L2), L1: JMP(L3) -> JMPZNZ(X, L3, L2) */
+ next = target_block->successors[0];
+ } else if ((target->opcode == ZEND_JMPZ || target->opcode == ZEND_JMPZNZ) &&
+ SAME_VAR(target->op1, last_op->op1)) {
+ /* JMPZNZ(X, L1, L2), L1: JMPZ(X, L3) -> JMPZNZ(X, L3, L2) */
+ next = target_block->successors[0];
+ } else if (target->opcode == ZEND_JMPNZ &&
+ SAME_VAR(target->op1, last_op->op1)) {
+ /* JMPZNZ(X, L1, L2), L1: X = JMPNZ(X, L3) -> JMPZNZ(X, L1+1, L2) */
+ next = target_block->successors[1];
+ } else {
+ break;
+ }
+ CHECK_LOOP(next);
+ block->successors[0] = next;
+ ++(*opt_count);
+ target_block = get_target_block(cfg, block, 0, opt_count);
}
- if (last_op->op1_type == IS_CONST) {
- if (!zend_is_true(&ZEND_OP1_LITERAL(last_op))) {
- /* JMPZNZ(false,L1,L2) -> JMP(L1) */
- literal_dtor(&ZEND_OP1_LITERAL(last_op));
- last_op->opcode = ZEND_JMP;
- SET_UNUSED(last_op->op1);
- SET_UNUSED(last_op->op2);
- DEL_SOURCE(block, block->successors[1]);
- block->successors_count = 1;
+ jmp_hitlist_count = 0;
+ follow_block = get_target_block(cfg, block, 1, opt_count);
+ while (follow_block->len == 1) {
+ target = op_array->opcodes + follow_block->start;
+
+ if (target->opcode == ZEND_JMP) {
+ /* JMPZNZ(X, L1, L2), L1: JMP(L3) -> JMPZNZ(X, L3, L2) */
+ next = follow_block->successors[0];
+ } else if (target->opcode == ZEND_JMPNZ &&
+ SAME_VAR(target->op1, last_op->op1)) {
+ /* JMPZNZ(X, L1, L2), L1: X = JMPNZ(X, L3) -> JMPZNZ(X, L1+1, L2) */
+ next = follow_block->successors[0];
+ } else if ((target->opcode == ZEND_JMPZ || target->opcode == ZEND_JMPZNZ) &&
+ SAME_VAR(target->op1, last_op->op1)) {
+ /* JMPZNZ(X, L1, L2), L1: JMPZ(X, L3) -> JMPZNZ(X, L3, L2) */
+ next = target_block->successors[1];
} else {
- /* JMPZNZ(true,L1,L2) -> JMP(L2) */
- literal_dtor(&ZEND_OP1_LITERAL(last_op));
- last_op->opcode = ZEND_JMP;
- SET_UNUSED(last_op->op1);
- SET_UNUSED(last_op->op2);
- DEL_SOURCE(block, block->successors[0]);
- block->successors_count = 1;
- block->successors[0] = block->successors[1];
+ break;
}
+ CHECK_LOOP(next);
+ block->successors[1] = next;
++(*opt_count);
- } else if (block->successors[0] == block->successors[1]) {
- /* both goto the same one - it's JMP */
- if (!(last_op->op1_type & (IS_VAR|IS_TMP_VAR))) {
- /* JMPZNZ(?,L,L) -> JMP(L) */
- last_op->opcode = ZEND_JMP;
- SET_UNUSED(last_op->op1);
- SET_UNUSED(last_op->op2);
- block->successors_count = 1;
- ++(*opt_count);
- }
- } else if (block->successors[0] == next) {
+ follow_block = get_target_block(cfg, block, 1, opt_count);
+ }
+
+ next_block = get_next_block(cfg, block);
+ if (target_block == follow_block &&
+ !(last_op->op1_type & (IS_VAR|IS_TMP_VAR))) {
+ /* JMPZNZ(?,L,L) -> JMP(L) */
+ last_op->opcode = ZEND_JMP;
+ SET_UNUSED(last_op->op1);
+ SET_UNUSED(last_op->op2);
+ last_op->extended_value = 0;
+ block->successors_count = 1;
+ ++(*opt_count);
+ } else if (target_block == next_block) {
/* jumping to next on Z - can follow to it and jump only on NZ */
/* JMPZNZ(X,L1,L2) L1: -> JMPNZ(X,L2) */
+ int tmp = block->successors[0];
last_op->opcode = ZEND_JMPNZ;
block->successors[0] = block->successors[1];
- block->successors[1] = next;
+ block->successors[1] = tmp;
++(*opt_count);
- /* no need to add source */
- } else if (block->successors[1] == next) {
+ } else if (follow_block == next_block) {
/* jumping to next on NZ - can follow to it and jump only on Z */
/* JMPZNZ(X,L1,L2) L2: -> JMPZ(X,L1) */
last_op->opcode = ZEND_JMPZ;
++(*opt_count);
- /* no need to add source */
- }
-
- if (last_op->opcode == ZEND_JMPZNZ) {
- zend_uchar same_type = last_op->op1_type;
- zend_uchar same_var = VAR_NUM_EX(last_op->op1);
- zend_op *target;
- zend_op *target_end;
- zend_basic_block *target_block = blocks + block->successors[0];
-
-next_target_znz:
- target = op_array->opcodes + target_block->start;
- target_end = target + target_block->len;
- while (target < target_end && target->opcode == ZEND_NOP) {
- target++;
- }
- /* next block is only NOP's */
- if (target == target_end) {
- target_block = blocks + target_block->successors[0];
- ++(*opt_count);
- goto next_target_znz;
- } else if ((target->opcode == ZEND_JMPZ || target->opcode == ZEND_JMPZNZ) &&
- (target->op1_type & (IS_TMP_VAR|IS_CV)) &&
- same_type == target->op1_type &&
- same_var == VAR_NUM_EX(target->op1) &&
- !(target_block->flags & ZEND_BB_PROTECTED)) {
- /* JMPZNZ(X, L1, L2), L1: JMPZ(X, L3) -> JMPZNZ(X, L3, L2) */
- DEL_SOURCE(block, block->successors[0]);
- block->successors[0] = target_block->successors[0];
- ADD_SOURCE(block, block->successors[0]);
- ++(*opt_count);
- } else if (target->opcode == ZEND_JMPNZ &&
- (target->op1_type & (IS_TMP_VAR|IS_CV)) &&
- same_type == target->op1_type &&
- same_var == VAR_NUM_EX(target->op1) &&
- !(target_block->flags & ZEND_BB_PROTECTED)) {
- /* JMPZNZ(X, L1, L2), L1: X = JMPNZ(X, L3) -> JMPZNZ(X, L1+1, L2) */
- DEL_SOURCE(block, block->successors[0]);
- block->successors[0] = target_block->successors[1];
- ADD_SOURCE(block, block->successors[0]);
- ++(*opt_count);
- } else if (target->opcode == ZEND_JMP &&
- !(target_block->flags & ZEND_BB_PROTECTED)) {
- /* JMPZNZ(X, L1, L2), L1: JMP(L3) -> JMPZNZ(X, L3, L2) */
- DEL_SOURCE(block, block->successors[0]);
- block->successors[0] = target_block->successors[0];
- ADD_SOURCE(block, block->successors[0]);
- ++(*opt_count);
- }
}
break;
}
@@ -1747,6 +1670,8 @@ static void zend_t_usage(zend_cfg *cfg, zend_op_array *op_array, zend_bitset use
case ZEND_POST_DEC:
case ZEND_POST_INC_OBJ:
case ZEND_POST_DEC_OBJ:
+ case ZEND_POST_INC_STATIC_PROP:
+ case ZEND_POST_DEC_STATIC_PROP:
opline->opcode -= 2;
opline->result_type = IS_UNUSED;
break;
@@ -1884,8 +1809,8 @@ void zend_optimize_cfg(zend_op_array *op_array, zend_optimizer_ctx *ctx)
zend_bitset usage;
void *checkpoint;
zend_op **Tsource;
- zend_uchar *same_t;
uint32_t opt_count;
+ int *jmp_hitlist;
/* Build CFG */
checkpoint = zend_arena_checkpoint(ctx->arena);
@@ -1905,8 +1830,8 @@ void zend_optimize_cfg(zend_op_array *op_array, zend_optimizer_ctx *ctx)
bitset_len = zend_bitset_len(op_array->last_var + op_array->T);
Tsource = zend_arena_calloc(&ctx->arena, op_array->last_var + op_array->T, sizeof(zend_op *));
- same_t = zend_arena_alloc(&ctx->arena, op_array->last_var + op_array->T);
usage = zend_arena_alloc(&ctx->arena, bitset_len * ZEND_BITSET_ELM_SIZE);
+ jmp_hitlist = zend_arena_alloc(&ctx->arena, cfg.blocks_count * sizeof(int));
blocks = cfg.blocks;
end = blocks + cfg.blocks_count;
@@ -1938,10 +1863,12 @@ void zend_optimize_cfg(zend_op_array *op_array, zend_optimizer_ctx *ctx)
}
}
+ opt_count = 0;
+
/* Jump optimization for each block */
for (b = blocks; b < end; b++) {
if (b->flags & ZEND_BB_REACHABLE) {
- zend_jmp_optimization(b, op_array, &cfg, same_t, &opt_count);
+ zend_jmp_optimization(b, op_array, &cfg, jmp_hitlist, &opt_count);
}
}
@@ -1956,8 +1883,6 @@ void zend_optimize_cfg(zend_op_array *op_array, zend_optimizer_ctx *ctx)
}
}
- zend_bitset_clear(usage, bitset_len);
- zend_t_usage(&cfg, op_array, usage, ctx);
assemble_code_blocks(&cfg, op_array, ctx);
if (ctx->debug_level & ZEND_DUMP_AFTER_BLOCK_PASS) {
diff --git a/ext/opcache/Optimizer/compact_literals.c b/ext/opcache/Optimizer/compact_literals.c
index f754dbaa44..0a99ac4140 100644
--- a/ext/opcache/Optimizer/compact_literals.c
+++ b/ext/opcache/Optimizer/compact_literals.c
@@ -168,13 +168,13 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
LITERAL_INFO(opline->op1.constant, LITERAL_CLASS, 2);
break;
case ZEND_DEFINED:
- LITERAL_INFO(opline->op1.constant, LITERAL_CONST, 2);
+ LITERAL_INFO(opline->op1.constant, LITERAL_CONST, 1);
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, 5);
- } else {
+ if (opline->op1.num & IS_CONSTANT_UNQUALIFIED_IN_NAMESPACE) {
LITERAL_INFO(opline->op2.constant, LITERAL_CONST, 3);
+ } else {
+ LITERAL_INFO(opline->op2.constant, LITERAL_CONST, 2);
}
break;
case ZEND_FETCH_CLASS_CONSTANT:
@@ -503,15 +503,10 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
}
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;
+ opline->extended_value = cache_size;
cache_size += sizeof(void *);
}
break;
diff --git a/ext/opcache/Optimizer/dce.c b/ext/opcache/Optimizer/dce.c
index 8370bdc779..2992bb60b3 100644
--- a/ext/opcache/Optimizer/dce.c
+++ b/ext/opcache/Optimizer/dce.c
@@ -241,6 +241,8 @@ static inline zend_bool may_have_side_effects(
}
}
return 0;
+ case ZEND_CHECK_VAR:
+ return (OP1_INFO() & MAY_BE_UNDEF) != 0;
default:
/* For everything we didn't handle, assume a side-effect */
return 1;
diff --git a/ext/opcache/Optimizer/dfa_pass.c b/ext/opcache/Optimizer/dfa_pass.c
index 5401c9df6a..d753c54a00 100644
--- a/ext/opcache/Optimizer/dfa_pass.c
+++ b/ext/opcache/Optimizer/dfa_pass.c
@@ -125,33 +125,6 @@ int zend_dfa_analyze_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx,
return SUCCESS;
}
-static zend_bool is_smart_branch_inhibiting_nop(
- zend_op_array *op_array, uint32_t target, uint32_t current,
- zend_basic_block *b, zend_basic_block *blocks_end)
-{
- uint32_t next;
- /* Target points one past the last non-nop instruction. Make sure there is one. */
- if (target == 0) {
- return 0;
- }
-
- /* Find the next instruction, skipping unreachable or empty blocks. */
- next = current + 1;
- if (next >= b->start + b->len) {
- do {
- b++;
- if (b == blocks_end) {
- return 0;
- }
- } while (!(b->flags & ZEND_BB_REACHABLE) || b->len == 0);
- next = b->start;
- }
-
- return (op_array->opcodes[next].opcode == ZEND_JMPZ ||
- op_array->opcodes[next].opcode == ZEND_JMPNZ) &&
- zend_is_smart_branch(op_array->opcodes + target - 1);
-}
-
static void zend_ssa_remove_nops(zend_op_array *op_array, zend_ssa *ssa, zend_optimizer_ctx *ctx)
{
zend_basic_block *blocks = ssa->cfg.blocks;
@@ -199,8 +172,7 @@ static void zend_ssa_remove_nops(zend_op_array *op_array, zend_ssa *ssa, zend_op
old_end = b->start + b->len;
while (i < old_end) {
shiftlist[i] = i - target;
- if (EXPECTED(op_array->opcodes[i].opcode != ZEND_NOP) ||
- is_smart_branch_inhibiting_nop(op_array, target, i, b, blocks_end)) {
+ if (EXPECTED(op_array->opcodes[i].opcode != ZEND_NOP)) {
if (i != target) {
op_array->opcodes[target] = op_array->opcodes[i];
ssa->ops[target] = ssa->ops[i];
@@ -312,6 +284,8 @@ static inline zend_bool can_elide_return_type_check(
zend_ssa_var_info *use_info = &ssa->var_info[ssa_op->op1_use];
zend_ssa_var_info *def_info = &ssa->var_info[ssa_op->op1_def];
+ /* TODO: It would be better to rewrite this without using def_info,
+ * which may not be an exact representation of the type. */
if (use_info->type & MAY_BE_REF) {
return 0;
}
@@ -322,7 +296,8 @@ static inline zend_bool can_elide_return_type_check(
}
/* These types are not represented exactly */
- if (ZEND_TYPE_CODE(info->type) == IS_CALLABLE || ZEND_TYPE_CODE(info->type) == IS_ITERABLE) {
+ if (ZEND_TYPE_IS_MASK(info->type)
+ && (ZEND_TYPE_MASK(info->type) & (MAY_BE_CALLABLE|MAY_BE_ITERABLE))) {
return 0;
}
@@ -481,6 +456,24 @@ int zend_dfa_optimize_calls(zend_op_array *op_array, zend_ssa *ssa)
MAKE_NOP(send_array);
removed_ops++;
+ op_num = call_info->caller_call_opline - op_array->opcodes;
+ ssa_op = ssa->ops + op_num;
+ if (ssa_op->result_def >= 0) {
+ int var = ssa_op->result_def;
+ int use = ssa->vars[var].use_chain;
+
+ if (ssa->vars[var].phi_use_chain == NULL) {
+ if (ssa->ops[use].op1_use == var
+ && ssa->ops[use].op1_use_chain == -1) {
+ call_info->caller_call_opline->result_type = IS_TMP_VAR;
+ op_array->opcodes[use].op1_type = IS_TMP_VAR;
+ } else if (ssa->ops[use].op2_use == var
+ && ssa->ops[use].op2_use_chain == -1) {
+ call_info->caller_call_opline->result_type = IS_TMP_VAR;
+ op_array->opcodes[use].op2_type = IS_TMP_VAR;
+ }
+ }
+ }
}
}
}
@@ -530,8 +523,7 @@ static void compress_block(zend_op_array *op_array, zend_basic_block *block)
while (block->len > 0) {
zend_op *opline = &op_array->opcodes[block->start + block->len - 1];
- if (opline->opcode == ZEND_NOP
- && (block->len == 1 || !zend_is_smart_branch(opline - 1))) {
+ if (opline->opcode == ZEND_NOP) {
block->len--;
} else {
break;
@@ -1165,8 +1157,64 @@ void zend_dfa_optimize_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx
/* Update opcodes */
op_array->opcodes[op_2].result_type = opline->op1_type;
op_array->opcodes[op_2].result.var = opline->op1.var;
+
MAKE_NOP(opline);
remove_nops = 1;
+
+ if (op_array->opcodes[op_2].opcode == ZEND_SUB
+ && op_array->opcodes[op_2].op1_type == op_array->opcodes[op_2].result_type
+ && op_array->opcodes[op_2].op1.var == op_array->opcodes[op_2].result.var
+ && op_array->opcodes[op_2].op2_type == IS_CONST
+ && Z_TYPE_P(CT_CONSTANT_EX(op_array, op_array->opcodes[op_2].op2.constant)) == IS_LONG
+ && Z_LVAL_P(CT_CONSTANT_EX(op_array, op_array->opcodes[op_2].op2.constant)) == 1
+ && ssa->ops[op_2].op1_use >= 0
+ && !(ssa->var_info[ssa->ops[op_2].op1_use].type & (MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))) {
+
+ op_array->opcodes[op_2].opcode = ZEND_PRE_DEC;
+ SET_UNUSED(op_array->opcodes[op_2].op2);
+ SET_UNUSED(op_array->opcodes[op_2].result);
+
+ ssa->ops[op_2].result_def = -1;
+ ssa->ops[op_2].op1_def = v;
+
+ } else if (op_array->opcodes[op_2].opcode == ZEND_ADD
+ && op_array->opcodes[op_2].op1_type == op_array->opcodes[op_2].result_type
+ && op_array->opcodes[op_2].op1.var == op_array->opcodes[op_2].result.var
+ && op_array->opcodes[op_2].op2_type == IS_CONST
+ && Z_TYPE_P(CT_CONSTANT_EX(op_array, op_array->opcodes[op_2].op2.constant)) == IS_LONG
+ && Z_LVAL_P(CT_CONSTANT_EX(op_array, op_array->opcodes[op_2].op2.constant)) == 1
+ && ssa->ops[op_2].op1_use >= 0
+ && !(ssa->var_info[ssa->ops[op_2].op1_use].type & (MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))) {
+
+ op_array->opcodes[op_2].opcode = ZEND_PRE_INC;
+ SET_UNUSED(op_array->opcodes[op_2].op2);
+ SET_UNUSED(op_array->opcodes[op_2].result);
+
+ ssa->ops[op_2].result_def = -1;
+ ssa->ops[op_2].op1_def = v;
+
+ } else if (op_array->opcodes[op_2].opcode == ZEND_ADD
+ && op_array->opcodes[op_2].op2_type == op_array->opcodes[op_2].result_type
+ && op_array->opcodes[op_2].op2.var == op_array->opcodes[op_2].result.var
+ && op_array->opcodes[op_2].op1_type == IS_CONST
+ && Z_TYPE_P(CT_CONSTANT_EX(op_array, op_array->opcodes[op_2].op1.constant)) == IS_LONG
+ && Z_LVAL_P(CT_CONSTANT_EX(op_array, op_array->opcodes[op_2].op1.constant)) == 1
+ && ssa->ops[op_2].op2_use >= 0
+ && !(ssa->var_info[ssa->ops[op_2].op2_use].type & (MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))) {
+
+ op_array->opcodes[op_2].opcode = ZEND_PRE_INC;
+ op_array->opcodes[op_2].op1_type = op_array->opcodes[op_2].op2_type;
+ op_array->opcodes[op_2].op1.var = op_array->opcodes[op_2].op2.var;
+ SET_UNUSED(op_array->opcodes[op_2].op2);
+ SET_UNUSED(op_array->opcodes[op_2].result);
+
+ ssa->ops[op_2].result_def = -1;
+ ssa->ops[op_2].op1_def = v;
+ ssa->ops[op_2].op1_use = ssa->ops[op_2].op2_use;
+ ssa->ops[op_2].op1_use_chain = ssa->ops[op_2].op2_use_chain;
+ ssa->ops[op_2].op2_use = -1;
+ ssa->ops[op_2].op2_use_chain = -1;
+ }
}
} else if (opline->op2_type == IS_CONST
|| ((opline->op2_type & (IS_TMP_VAR|IS_VAR|IS_CV))
diff --git a/ext/opcache/Optimizer/escape_analysis.c b/ext/opcache/Optimizer/escape_analysis.c
index c561bec9dc..a13f69cdf0 100644
--- a/ext/opcache/Optimizer/escape_analysis.c
+++ b/ext/opcache/Optimizer/escape_analysis.c
@@ -176,7 +176,7 @@ static int is_allocation_def(zend_op_array *op_array, zend_ssa *ssa, int def, in
case ZEND_NEW:
/* objects with destructors should escape */
if (opline->op1_type == IS_CONST) {
- zend_class_entry *ce = get_class_entry(script, Z_STR_P(CRT_CONSTANT_EX(op_array, opline, opline->op1, ssa->rt_constants)+1));
+ zend_class_entry *ce = get_class_entry(script, Z_STR_P(CRT_CONSTANT(opline->op1)+1));
uint32_t forbidden_flags = ZEND_ACC_INHERITED
/* These flags will always cause an exception */
| ZEND_ACC_IMPLICIT_ABSTRACT_CLASS | ZEND_ACC_EXPLICIT_ABSTRACT_CLASS
@@ -191,7 +191,7 @@ static int is_allocation_def(zend_op_array *op_array, zend_ssa *ssa, int def, in
break;
case ZEND_QM_ASSIGN:
if (opline->op1_type == IS_CONST
- && Z_TYPE_P(CRT_CONSTANT_EX(op_array, opline, opline->op1, ssa->rt_constants)) == IS_ARRAY) {
+ && Z_TYPE_P(CRT_CONSTANT(opline->op1)) == IS_ARRAY) {
return 1;
}
if (opline->op1_type == IS_CV && (OP1_INFO() & MAY_BE_ARRAY)) {
@@ -208,7 +208,7 @@ static int is_allocation_def(zend_op_array *op_array, zend_ssa *ssa, int def, in
switch (opline->opcode) {
case ZEND_ASSIGN:
if (opline->op2_type == IS_CONST
- && Z_TYPE_P(CRT_CONSTANT_EX(op_array, opline, opline->op2, ssa->rt_constants)) == IS_ARRAY) {
+ && Z_TYPE_P(CRT_CONSTANT(opline->op2)) == IS_ARRAY) {
return 1;
}
if (opline->op2_type == IS_CV && (OP2_INFO() & MAY_BE_ARRAY)) {
@@ -245,7 +245,7 @@ static int is_local_def(zend_op_array *op_array, zend_ssa *ssa, int def, int var
case ZEND_NEW:
/* objects with destructors should escape */
if (opline->op1_type == IS_CONST) {
- zend_class_entry *ce = get_class_entry(script, Z_STR_P(CRT_CONSTANT_EX(op_array, opline, opline->op1, ssa->rt_constants)+1));
+ zend_class_entry *ce = get_class_entry(script, Z_STR_P(CRT_CONSTANT(opline->op1)+1));
if (ce && !ce->create_object && !ce->constructor &&
!ce->destructor && !ce->__get && !ce->__set &&
!(ce->ce_flags & ZEND_ACC_INHERITED)) {
diff --git a/ext/opcache/Optimizer/optimize_func_calls.c b/ext/opcache/Optimizer/optimize_func_calls.c
index ae707a2409..ea2b904a0f 100644
--- a/ext/opcache/Optimizer/optimize_func_calls.c
+++ b/ext/opcache/Optimizer/optimize_func_calls.c
@@ -126,7 +126,7 @@ static void zend_try_inline_call(zend_op_array *op_array, zend_op *fcall, zend_o
i = fcall->extended_value;
do {
- if (Z_TYPE_P(RT_CONSTANT(&func->op_array.opcodes[i], func->op_array.opcodes[i].op2)) == IS_CONSTANT_AST) {
+ if (Z_TYPE_P(CRT_CONSTANT_EX(&func->op_array, &func->op_array.opcodes[i], func->op_array.opcodes[i].op2)) == IS_CONSTANT_AST) {
return;
}
i++;
@@ -136,7 +136,7 @@ static void zend_try_inline_call(zend_op_array *op_array, zend_op *fcall, zend_o
if (RETURN_VALUE_USED(opline)) {
zval zv;
- ZVAL_COPY(&zv, RT_CONSTANT(ret_opline, ret_opline->op1));
+ ZVAL_COPY(&zv, CRT_CONSTANT_EX(&func->op_array, ret_opline, ret_opline->op1));
opline->opcode = ZEND_QM_ASSIGN;
opline->op1_type = IS_CONST;
opline->op1.constant = zend_optimizer_add_literal(op_array, &zv);
@@ -173,7 +173,7 @@ void zend_optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx)
case ZEND_INIT_FCALL:
case ZEND_NEW:
call_stack[call].func = zend_optimizer_get_called_func(
- ctx->script, op_array, opline, 0);
+ ctx->script, op_array, opline);
call_stack[call].try_inline = opline->opcode != ZEND_NEW;
/* break missing intentionally */
case ZEND_INIT_DYNAMIC_CALL:
diff --git a/ext/opcache/Optimizer/pass1_5.c b/ext/opcache/Optimizer/pass1.c
index 8ae1d34fc0..2e9e547175 100644
--- a/ext/opcache/Optimizer/pass1_5.c
+++ b/ext/opcache/Optimizer/pass1.c
@@ -19,10 +19,11 @@
+----------------------------------------------------------------------+
*/
-/* pass 1
- * - substitute persistent constants (true, false, null, etc)
- * - perform compile-time evaluation of constant binary and unary operations
- * - convert CAST(IS_BOOL,x) into BOOL(x)
+/* pass 1 (Simple local optimizations)
+ * - persistent constant substitution (true, false, null, etc)
+ * - constant casting (ADD expects numbers, CONCAT strings, etc)
+ * - constant expression evaluation
+ * - optimize constant conditional JMPs
* - pre-evaluate constant function calls
* - eliminate FETCH $GLOBALS followed by FETCH_DIM/UNSET_DIM/ISSET_ISEMPTY_DIM
*/
@@ -37,7 +38,6 @@
void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx)
{
- int i = 0;
zend_op *opline = op_array->opcodes;
zend_op *end = opline + op_array->last;
zend_bool collect_constants = (ZEND_OPTIMIZER_PASS_15 & ctx->optimization_level)?
@@ -49,21 +49,80 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx)
case ZEND_SUB:
case ZEND_MUL:
case ZEND_DIV:
- case ZEND_MOD:
case ZEND_POW:
+ if (opline->op1_type == IS_CONST) {
+ if (Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING) {
+ /* don't optimise if it should produce a runtime numeric string error */
+ if (is_numeric_string(Z_STRVAL(ZEND_OP1_LITERAL(opline)), Z_STRLEN(ZEND_OP1_LITERAL(opline)), NULL, NULL, 0)) {
+ convert_scalar_to_number(&ZEND_OP1_LITERAL(opline));
+ }
+ }
+ }
+ if (opline->op2_type == IS_CONST) {
+ if (Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING) {
+ /* don't optimise if it should produce a runtime numeric string error */
+ if (is_numeric_string(Z_STRVAL(ZEND_OP2_LITERAL(opline)), Z_STRLEN(ZEND_OP2_LITERAL(opline)), NULL, NULL, 0)) {
+ convert_scalar_to_number(&ZEND_OP2_LITERAL(opline));
+ }
+ }
+ if (opline->op1_type == IS_CONST) {
+ goto constant_binary_op;
+ }
+ }
+ break;
+
+ case ZEND_MOD:
case ZEND_SL:
case ZEND_SR:
+ if (opline->op1_type == IS_CONST) {
+ if (Z_TYPE(ZEND_OP1_LITERAL(opline)) != IS_LONG) {
+ /* don't optimise if it should produce a runtime numeric string error */
+ if (!(Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING
+ && !is_numeric_string(Z_STRVAL(ZEND_OP1_LITERAL(opline)), Z_STRLEN(ZEND_OP1_LITERAL(opline)), NULL, NULL, 0))) {
+ convert_to_long(&ZEND_OP1_LITERAL(opline));
+ }
+ }
+ }
+ if (opline->op2_type == IS_CONST) {
+ if (Z_TYPE(ZEND_OP2_LITERAL(opline)) != IS_LONG) {
+ /* don't optimise if it should produce a runtime numeric string error */
+ if (!(Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING
+ && !is_numeric_string(Z_STRVAL(ZEND_OP2_LITERAL(opline)), Z_STRLEN(ZEND_OP2_LITERAL(opline)), NULL, NULL, 0))) {
+ convert_to_long(&ZEND_OP2_LITERAL(opline));
+ }
+ }
+ if (opline->op1_type == IS_CONST) {
+ goto constant_binary_op;
+ }
+ }
+ break;
+
case ZEND_CONCAT:
case ZEND_FAST_CONCAT:
+ if (opline->op1_type == IS_CONST) {
+ if (Z_TYPE(ZEND_OP1_LITERAL(opline)) != IS_STRING) {
+ convert_to_string(&ZEND_OP1_LITERAL(opline));
+ }
+ }
+ if (opline->op2_type == IS_CONST) {
+ if (Z_TYPE(ZEND_OP2_LITERAL(opline)) != IS_STRING) {
+ convert_to_string(&ZEND_OP2_LITERAL(opline));
+ }
+ if (opline->op1_type == IS_CONST) {
+ goto constant_binary_op;
+ }
+ }
+ break;
+
+ case ZEND_BW_OR:
+ case ZEND_BW_AND:
+ case ZEND_BW_XOR:
case ZEND_IS_EQUAL:
case ZEND_IS_NOT_EQUAL:
case ZEND_IS_SMALLER:
case ZEND_IS_SMALLER_OR_EQUAL:
case ZEND_IS_IDENTICAL:
case ZEND_IS_NOT_IDENTICAL:
- case ZEND_BW_OR:
- case ZEND_BW_AND:
- case ZEND_BW_XOR:
case ZEND_BOOL_XOR:
case ZEND_SPACESHIP:
case ZEND_CASE:
@@ -72,6 +131,7 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx)
/* binary operation with constant operands */
zval result;
+constant_binary_op:
if (zend_optimizer_eval_binary_op(&result, opline->opcode, &ZEND_OP1_LITERAL(opline), &ZEND_OP2_LITERAL(opline)) == SUCCESS) {
literal_dtor(&ZEND_OP1_LITERAL(opline));
literal_dtor(&ZEND_OP2_LITERAL(opline));
@@ -86,6 +146,37 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx)
}
break;
+ case ZEND_ASSIGN_OP:
+ if (opline->op2_type == IS_CONST) {
+ if (opline->extended_value == ZEND_ADD
+ || opline->extended_value == ZEND_SUB
+ || opline->extended_value == ZEND_MUL
+ || opline->extended_value == ZEND_DIV
+ || opline->extended_value == ZEND_POW) {
+ if (Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING) {
+ /* don't optimise if it should produce a runtime numeric string error */
+ if (is_numeric_string(Z_STRVAL(ZEND_OP2_LITERAL(opline)), Z_STRLEN(ZEND_OP2_LITERAL(opline)), NULL, NULL, 0)) {
+ convert_scalar_to_number(&ZEND_OP2_LITERAL(opline));
+ }
+ }
+ } else if (opline->extended_value == ZEND_MOD
+ || opline->extended_value == ZEND_SL
+ || opline->extended_value == ZEND_SR) {
+ if (Z_TYPE(ZEND_OP2_LITERAL(opline)) != IS_LONG) {
+ /* don't optimise if it should produce a runtime numeric string error */
+ if (!(Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING
+ && !is_numeric_string(Z_STRVAL(ZEND_OP2_LITERAL(opline)), Z_STRLEN(ZEND_OP2_LITERAL(opline)), NULL, NULL, 0))) {
+ convert_to_long(&ZEND_OP2_LITERAL(opline));
+ }
+ }
+ } else if (opline->extended_value == ZEND_CONCAT) {
+ if (Z_TYPE(ZEND_OP2_LITERAL(opline)) != IS_STRING) {
+ convert_to_string(&ZEND_OP2_LITERAL(opline));
+ }
+ }
+ }
+ break;
+
case ZEND_CAST:
if (opline->op1_type == IS_CONST) {
/* cast of constant operand */
@@ -103,12 +194,6 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx)
break;
}
}
-
- if (opline->extended_value == _IS_BOOL) {
- /* T = CAST(X, IS_BOOL) => T = BOOL(X) */
- opline->opcode = ZEND_BOOL;
- opline->extended_value = 0;
- }
break;
case ZEND_BW_NOT:
@@ -559,6 +644,71 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx)
}
break;
+ case ZEND_JMPZ_EX:
+ case ZEND_JMPNZ_EX:
+ /* convert Ti = JMPZ_EX(C, L) => Ti = QM_ASSIGN(C)
+ in case we know it wouldn't jump */
+ if (opline->op1_type == IS_CONST) {
+ if (zend_is_true(&ZEND_OP1_LITERAL(opline))) {
+ if (opline->opcode == ZEND_JMPZ_EX) {
+ opline->opcode = ZEND_QM_ASSIGN;
+ zval_ptr_dtor_nogc(&ZEND_OP1_LITERAL(opline));
+ ZVAL_TRUE(&ZEND_OP1_LITERAL(opline));
+ opline->op2.num = 0;
+ break;
+ }
+ } else {
+ if (opline->opcode == ZEND_JMPNZ_EX) {
+ opline->opcode = ZEND_QM_ASSIGN;
+ zval_ptr_dtor_nogc(&ZEND_OP1_LITERAL(opline));
+ ZVAL_FALSE(&ZEND_OP1_LITERAL(opline));
+ opline->op2.num = 0;
+ break;
+ }
+ }
+ }
+ collect_constants = 0;
+ break;
+
+ case ZEND_JMPZ:
+ case ZEND_JMPNZ:
+ if (opline->op1_type == IS_CONST) {
+ int should_jmp = zend_is_true(&ZEND_OP1_LITERAL(opline));
+
+ if (opline->opcode == ZEND_JMPZ) {
+ should_jmp = !should_jmp;
+ }
+ literal_dtor(&ZEND_OP1_LITERAL(opline));
+ opline->op1_type = IS_UNUSED;
+ if (should_jmp) {
+ opline->opcode = ZEND_JMP;
+ COPY_NODE(opline->op1, opline->op2);
+ opline->op2.num = 0;
+ } else {
+ MAKE_NOP(opline);
+ break;
+ }
+ }
+ collect_constants = 0;
+ break;
+
+ case ZEND_JMPZNZ:
+ if (opline->op1_type == IS_CONST) {
+ zend_op *target_opline;
+
+ if (zend_is_true(&ZEND_OP1_LITERAL(opline))) {
+ target_opline = ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value); /* JMPNZ */
+ } else {
+ target_opline = ZEND_OP2_JMP_ADDR(opline); /* JMPZ */
+ }
+ literal_dtor(&ZEND_OP1_LITERAL(opline));
+ ZEND_SET_OP_JMP_ADDR(opline, opline->op1, target_opline);
+ opline->op1_type = IS_UNUSED;
+ opline->opcode = ZEND_JMP;
+ }
+ collect_constants = 0;
+ break;
+
case ZEND_RETURN:
case ZEND_RETURN_BY_REF:
case ZEND_GENERATOR_RETURN:
@@ -568,11 +718,6 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx)
case ZEND_FAST_CALL:
case ZEND_FAST_RET:
case ZEND_JMP:
- case ZEND_JMPZNZ:
- case ZEND_JMPZ:
- case ZEND_JMPNZ:
- case ZEND_JMPZ_EX:
- case ZEND_JMPNZ_EX:
case ZEND_FE_RESET_R:
case ZEND_FE_RESET_RW:
case ZEND_FE_FETCH_R:
@@ -584,6 +729,5 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx)
break;
}
opline++;
- i++;
}
}
diff --git a/ext/opcache/Optimizer/pass2.c b/ext/opcache/Optimizer/pass2.c
deleted file mode 100644
index 01e118e7e3..0000000000
--- a/ext/opcache/Optimizer/pass2.c
+++ /dev/null
@@ -1,225 +0,0 @@
-/*
- +----------------------------------------------------------------------+
- | 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: |
- | http://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 2:
- * - convert non-numeric constants to numeric constants in numeric operators
- * - optimize constant conditional JMPs
- */
-
-#include "php.h"
-#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_pass2(zend_op_array *op_array)
-{
- zend_op *opline;
- zend_op *end = op_array->opcodes + op_array->last;
-
- opline = op_array->opcodes;
- while (opline < end) {
- switch (opline->opcode) {
- case ZEND_ADD:
- case ZEND_SUB:
- case ZEND_MUL:
- case ZEND_DIV:
- case ZEND_POW:
- if (opline->op1_type == IS_CONST) {
- if (Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING) {
- /* don't optimise if it should produce a runtime numeric string error */
- if (is_numeric_string(Z_STRVAL(ZEND_OP1_LITERAL(opline)), Z_STRLEN(ZEND_OP1_LITERAL(opline)), NULL, NULL, 0)) {
- convert_scalar_to_number(&ZEND_OP1_LITERAL(opline));
- }
- }
- }
- if (opline->op2_type == IS_CONST) {
- if (Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING) {
- /* don't optimise if it should produce a runtime numeric string error */
- if (is_numeric_string(Z_STRVAL(ZEND_OP2_LITERAL(opline)), Z_STRLEN(ZEND_OP2_LITERAL(opline)), NULL, NULL, 0)) {
- convert_scalar_to_number(&ZEND_OP2_LITERAL(opline));
- }
- }
- }
- break;
-
- case ZEND_MOD:
- case ZEND_SL:
- case ZEND_SR:
- if (opline->op1_type == IS_CONST) {
- if (Z_TYPE(ZEND_OP1_LITERAL(opline)) != IS_LONG) {
- /* don't optimise if it should produce a runtime numeric string error */
- if (!(Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING
- && !is_numeric_string(Z_STRVAL(ZEND_OP1_LITERAL(opline)), Z_STRLEN(ZEND_OP1_LITERAL(opline)), NULL, NULL, 0))) {
- convert_to_long(&ZEND_OP1_LITERAL(opline));
- }
- }
- }
- if (opline->op2_type == IS_CONST) {
- if (Z_TYPE(ZEND_OP2_LITERAL(opline)) != IS_LONG) {
- /* don't optimise if it should produce a runtime numeric string error */
- if (!(Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING
- && !is_numeric_string(Z_STRVAL(ZEND_OP2_LITERAL(opline)), Z_STRLEN(ZEND_OP2_LITERAL(opline)), NULL, NULL, 0))) {
- convert_to_long(&ZEND_OP2_LITERAL(opline));
- }
- }
- }
- break;
-
- case ZEND_CONCAT:
- case ZEND_FAST_CONCAT:
- if (opline->op1_type == IS_CONST) {
- if (Z_TYPE(ZEND_OP1_LITERAL(opline)) != IS_STRING) {
- convert_to_string(&ZEND_OP1_LITERAL(opline));
- }
- }
- if (opline->op2_type == IS_CONST) {
- if (Z_TYPE(ZEND_OP2_LITERAL(opline)) != IS_STRING) {
- convert_to_string(&ZEND_OP2_LITERAL(opline));
- }
- }
- break;
-
- case ZEND_ASSIGN_OP:
- if (opline->op2_type == IS_CONST) {
- if (opline->extended_value == ZEND_ADD
- || opline->extended_value == ZEND_SUB
- || opline->extended_value == ZEND_MUL
- || opline->extended_value == ZEND_DIV
- || opline->extended_value == ZEND_POW) {
- if (Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING) {
- /* don't optimise if it should produce a runtime numeric string error */
- if (is_numeric_string(Z_STRVAL(ZEND_OP2_LITERAL(opline)), Z_STRLEN(ZEND_OP2_LITERAL(opline)), NULL, NULL, 0)) {
- convert_scalar_to_number(&ZEND_OP2_LITERAL(opline));
- }
- }
- } else if (opline->extended_value == ZEND_MOD
- || opline->extended_value == ZEND_SL
- || opline->extended_value == ZEND_SR) {
- if (Z_TYPE(ZEND_OP2_LITERAL(opline)) != IS_LONG) {
- /* don't optimise if it should produce a runtime numeric string error */
- if (!(Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING
- && !is_numeric_string(Z_STRVAL(ZEND_OP2_LITERAL(opline)), Z_STRLEN(ZEND_OP2_LITERAL(opline)), NULL, NULL, 0))) {
- convert_to_long(&ZEND_OP2_LITERAL(opline));
- }
- }
- } else if (opline->extended_value == ZEND_CONCAT) {
- if (Z_TYPE(ZEND_OP2_LITERAL(opline)) != IS_STRING) {
- convert_to_string(&ZEND_OP2_LITERAL(opline));
- }
- }
- }
- break;
-
- case ZEND_JMPZ_EX:
- case ZEND_JMPNZ_EX:
- /* convert Ti = JMPZ_EX(Ti, L) to JMPZ(Ti, L) */
-#if 0
- /* Disabled unsafe pattern: in conjunction with
- * ZEND_VM_SMART_BRANCH() this may improperly eliminate
- * assignment to Ti.
- */
- if (opline->op1_type == IS_TMP_VAR &&
- opline->result_type == IS_TMP_VAR &&
- opline->op1.var == opline->result.var) {
- opline->opcode -= 3;
- SET_UNUSED(opline->result);
- } else
-#endif
- /* convert Ti = JMPZ_EX(C, L) => Ti = QM_ASSIGN(C)
- in case we know it wouldn't jump */
- if (opline->op1_type == IS_CONST) {
- int should_jmp = zend_is_true(&ZEND_OP1_LITERAL(opline));
- if (opline->opcode == ZEND_JMPZ_EX) {
- should_jmp = !should_jmp;
- }
- if (!should_jmp) {
- opline->opcode = ZEND_QM_ASSIGN;
- SET_UNUSED(opline->op2);
- }
- }
- break;
-
- case ZEND_JMPZ:
- case ZEND_JMPNZ:
- if (opline->op1_type == IS_CONST) {
- int should_jmp = zend_is_true(&ZEND_OP1_LITERAL(opline));
-
- if (opline->opcode == ZEND_JMPZ) {
- should_jmp = !should_jmp;
- }
- literal_dtor(&ZEND_OP1_LITERAL(opline));
- opline->op1_type = IS_UNUSED;
- if (should_jmp) {
- opline->opcode = ZEND_JMP;
- COPY_NODE(opline->op1, opline->op2);
- } else {
- MAKE_NOP(opline);
- }
- break;
- }
- if ((opline + 1)->opcode == ZEND_JMP) {
- /* JMPZ(X, L1), JMP(L2) => JMPZNZ(X, L1, L2) */
- /* JMPNZ(X, L1), JMP(L2) => JMPZNZ(X, L2, L1) */
- if (ZEND_OP2_JMP_ADDR(opline) == ZEND_OP1_JMP_ADDR(opline + 1)) {
- /* JMPZ(X, L1), JMP(L1) => NOP, JMP(L1) */
- if (opline->op1_type == IS_CV) {
- opline->opcode = ZEND_CHECK_VAR;
- opline->op2.num = 0;
- } else if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) {
- opline->opcode = ZEND_FREE;
- opline->op2.num = 0;
- } else {
- MAKE_NOP(opline);
- }
- } else {
- if (opline->opcode == ZEND_JMPZ) {
- opline->extended_value = ZEND_OPLINE_TO_OFFSET(opline, ZEND_OP1_JMP_ADDR(opline + 1));
- } else {
- opline->extended_value = ZEND_OPLINE_TO_OFFSET(opline, ZEND_OP2_JMP_ADDR(opline));
- ZEND_SET_OP_JMP_ADDR(opline, opline->op2, ZEND_OP1_JMP_ADDR(opline + 1));
- }
- opline->opcode = ZEND_JMPZNZ;
- }
- }
- break;
-
- case ZEND_JMPZNZ:
- if (opline->op1_type == IS_CONST) {
- zend_op *target_opline;
-
- if (zend_is_true(&ZEND_OP1_LITERAL(opline))) {
- target_opline = ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value); /* JMPNZ */
- } else {
- target_opline = ZEND_OP2_JMP_ADDR(opline); /* JMPZ */
- }
- literal_dtor(&ZEND_OP1_LITERAL(opline));
- ZEND_SET_OP_JMP_ADDR(opline, opline->op1, target_opline);
- opline->op1_type = IS_UNUSED;
- opline->opcode = ZEND_JMP;
- }
- break;
- }
- opline++;
- }
-}
diff --git a/ext/opcache/Optimizer/pass3.c b/ext/opcache/Optimizer/pass3.c
index 5bbb2b0854..a4abe2f8d3 100644
--- a/ext/opcache/Optimizer/pass3.c
+++ b/ext/opcache/Optimizer/pass3.c
@@ -19,10 +19,8 @@
+----------------------------------------------------------------------+
*/
-/* pass 3:
- * - optimize $i = $i+expr to $i+=expr
+/* pass 3: (Jump optimization)
* - optimize series of JMPs
- * - change $i++ to ++$i where possible
*/
#include "php.h"
@@ -34,388 +32,325 @@
#include "zend_vm.h"
/* we use "jmp_hitlist" to avoid infinity loops during jmp optimization */
-#define CHECK_JMP(target, label) \
- for (i=0; i<jmp_hitlist_count; i++) { \
- if (jmp_hitlist[i] == ZEND_OP1_JMP_ADDR(target)) { \
- goto label; \
- } \
- } \
- jmp_hitlist[jmp_hitlist_count++] = ZEND_OP1_JMP_ADDR(target);
+static zend_always_inline int in_hitlist(zend_op *target, zend_op **jmp_hitlist, int jmp_hitlist_count)
+{
+ int i;
-#define CHECK_JMP2(target, label) \
- for (i=0; i<jmp_hitlist_count; i++) { \
- if (jmp_hitlist[i] == ZEND_OP2_JMP_ADDR(target)) { \
- goto label; \
- } \
- } \
- jmp_hitlist[jmp_hitlist_count++] = ZEND_OP2_JMP_ADDR(target);
+ for (i = 0; i < jmp_hitlist_count; i++) {
+ if (jmp_hitlist[i] == target) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+#define CHECK_LOOP(target) \
+ if (EXPECTED(!in_hitlist(target, jmp_hitlist, jmp_hitlist_count))) { \
+ jmp_hitlist[jmp_hitlist_count++] = target; \
+ } else { \
+ break; \
+ }
void zend_optimizer_pass3(zend_op_array *op_array, zend_optimizer_ctx *ctx)
{
zend_op *opline;
- zend_op *end = op_array->opcodes + op_array->last;
+ zend_op *end;
+ zend_op *target;
zend_op **jmp_hitlist;
int jmp_hitlist_count;
- int i;
- uint32_t opline_num = 0;
ALLOCA_FLAG(use_heap);
jmp_hitlist = (zend_op**)do_alloca(sizeof(zend_op*)*op_array->last, use_heap);
opline = op_array->opcodes;
+ end = opline + op_array->last;
while (opline < end) {
- jmp_hitlist_count = 0;
switch (opline->opcode) {
- case ZEND_ADD:
- case ZEND_SUB:
- case ZEND_MUL:
- case ZEND_DIV:
- case ZEND_MOD:
- case ZEND_POW:
- case ZEND_CONCAT:
- case ZEND_SL:
- case ZEND_SR:
- case ZEND_BW_OR:
- case ZEND_BW_AND:
- case ZEND_BW_XOR:
- {
- zend_op *next_opline = opline + 1;
-
- while (next_opline < end && next_opline->opcode == ZEND_NOP) {
- ++next_opline;
- }
+ case ZEND_JMP:
+ jmp_hitlist_count = 0;
- if (next_opline >= end || next_opline->opcode != ZEND_ASSIGN) {
+ target = ZEND_OP1_JMP_ADDR(opline);
+ while (1) {
+ if (target->opcode == ZEND_JMP) {
+ /* convert JMP L1 ... L1: JMP L2 to JMP L2 .. L1: JMP L2 */
+ target = ZEND_OP1_JMP_ADDR(target);
+ CHECK_LOOP(target);
+ } else if (target->opcode == ZEND_NOP) {
+ target = target + 1;
+ } else {
break;
}
-
- /* change $i=expr+$i to $i=$i+expr so that the following optimization
- * works on it. Only do this if we are ignoring operator overloading,
- * as operand order might be significant otherwise. */
- if ((ctx->optimization_level & ZEND_OPTIMIZER_IGNORE_OVERLOADING)
- && (opline->op2_type & (IS_VAR | IS_CV))
- && opline->op2.var == next_opline->op1.var &&
- (opline->opcode == ZEND_ADD ||
- opline->opcode == ZEND_MUL ||
- opline->opcode == ZEND_BW_OR ||
- opline->opcode == ZEND_BW_AND ||
- opline->opcode == ZEND_BW_XOR)) {
- zend_uchar tmp_type = opline->op1_type;
- znode_op tmp = opline->op1;
-
- if (opline->opcode != ZEND_ADD
- || (opline->op1_type == IS_CONST
- && Z_TYPE(ZEND_OP1_LITERAL(opline)) != IS_ARRAY)) {
- /* protection from array add: $a = array + $a is not commutative! */
- COPY_NODE(opline->op1, opline->op2);
- COPY_NODE(opline->op2, tmp);
- }
- }
-
- if (ZEND_IS_BINARY_ASSIGN_OP_OPCODE(opline->opcode)
- && (opline->op1_type & (IS_VAR | IS_CV))
- && opline->op1.var == next_opline->op1.var
- && opline->op1_type == next_opline->op1_type) {
- opline->extended_value = opline->opcode;
- opline->opcode = ZEND_ASSIGN_OP;
- COPY_NODE(opline->result, next_opline->result);
- MAKE_NOP(next_opline);
- opline++;
- opline_num++;
- }
+ ZEND_SET_OP_JMP_ADDR(opline, opline->op1, target);
}
- break;
- case ZEND_JMP:
- if (op_array->fn_flags & ZEND_ACC_HAS_FINALLY_BLOCK) {
- break;
- }
-
- /* convert L: JMP L+1 to NOP */
- if (ZEND_OP1_JMP_ADDR(opline) == opline + 1) {
+ if (target == opline + 1) {
+ /* convert L: JMP L+1 to NOP */
MAKE_NOP(opline);
- goto done_jmp_optimization;
- }
-
- /* convert JMP L1 ... L1: JMP L2 to JMP L2 .. L1: JMP L2 */
- while (ZEND_OP1_JMP_ADDR(opline) < end
- && ZEND_OP1_JMP_ADDR(opline)->opcode == ZEND_JMP) {
- zend_op *target = ZEND_OP1_JMP_ADDR(opline);
- CHECK_JMP(target, done_jmp_optimization);
- ZEND_SET_OP_JMP_ADDR(opline, opline->op1, ZEND_OP1_JMP_ADDR(target));
+ } else if (target->opcode == ZEND_JMPZNZ) {
+ /* JMP L, L: JMPZNZ L1,L2 -> JMPZNZ L1,L2 */
+ *opline = *target;
+ if (opline->op1_type == IS_CONST) {
+ zval zv;
+ ZVAL_COPY(&zv, &ZEND_OP1_LITERAL(opline));
+ opline->op1.constant = zend_optimizer_add_literal(op_array, &zv);
+ }
+ goto optimize_jmpznz;
+ } else if ((target->opcode == ZEND_RETURN ||
+ target->opcode == ZEND_RETURN_BY_REF ||
+ target->opcode == ZEND_GENERATOR_RETURN ||
+ target->opcode == ZEND_EXIT) &&
+ !(op_array->fn_flags & ZEND_ACC_HAS_FINALLY_BLOCK)) {
+ /* JMP L, L: RETURN to immediate RETURN */
+ *opline = *target;
+ if (opline->op1_type == IS_CONST) {
+ zval zv;
+ ZVAL_COPY(&zv, &ZEND_OP1_LITERAL(opline));
+ opline->op1.constant = zend_optimizer_add_literal(op_array, &zv);
+ }
+ } else if (opline > op_array->opcodes &&
+ ((opline-1)->opcode == ZEND_JMPZ ||
+ (opline-1)->opcode == ZEND_JMPNZ)) {
+ if (ZEND_OP2_JMP_ADDR(opline-1) == target) {
+ /* JMPZ(X,L1), JMP(L1) -> NOP, JMP(L1) */
+ if ((opline-1)->op1_type == IS_CV) {
+ (opline-1)->opcode = ZEND_CHECK_VAR;
+ (opline-1)->op2.num = 0;
+ } else if ((opline-1)->op1_type & (IS_TMP_VAR|IS_VAR)) {
+ (opline-1)->opcode = ZEND_FREE;
+ (opline-1)->op2.num = 0;
+ } else {
+ MAKE_NOP(opline-1);
+ }
+ } else {
+ /* JMPZ(X,L1), JMP(L2) -> JMPZNZ(X,L1,L2) */
+ if ((opline-1)->opcode == ZEND_JMPZ) {
+ (opline-1)->extended_value = ZEND_OPLINE_TO_OFFSET((opline-1), target);
+ } else {
+ (opline-1)->extended_value = ZEND_OPLINE_TO_OFFSET((opline-1), ZEND_OP2_JMP_ADDR(opline-1));
+ ZEND_SET_OP_JMP_ADDR((opline-1), (opline-1)->op2, target);
+ }
+ (opline-1)->opcode = ZEND_JMPZNZ;
+ }
}
break;
case ZEND_JMP_SET:
case ZEND_COALESCE:
- if (op_array->fn_flags & ZEND_ACC_HAS_FINALLY_BLOCK) {
- break;
- }
+ jmp_hitlist_count = 0;
- while (ZEND_OP2_JMP_ADDR(opline) < end) {
- zend_op *target = ZEND_OP2_JMP_ADDR(opline);
+ target = ZEND_OP2_JMP_ADDR(opline);
+ while (1) {
if (target->opcode == ZEND_JMP) {
- ZEND_SET_OP_JMP_ADDR(opline, opline->op2, ZEND_OP1_JMP_ADDR(target));
+ target = ZEND_OP1_JMP_ADDR(target);
+ CHECK_LOOP(target);
+ } else if (target->opcode == ZEND_NOP) {
+ target = target + 1;
} else {
break;
}
+ ZEND_SET_OP_JMP_ADDR(opline, opline->op2, target);
}
break;
+
case ZEND_JMPZ:
case ZEND_JMPNZ:
- if (op_array->fn_flags & ZEND_ACC_HAS_FINALLY_BLOCK) {
- break;
- }
-
- while (ZEND_OP2_JMP_ADDR(opline) < end) {
- zend_op *target = ZEND_OP2_JMP_ADDR(opline);
+ jmp_hitlist_count = 0;
+ target = ZEND_OP2_JMP_ADDR(opline);
+ while (1) {
if (target->opcode == ZEND_JMP) {
/* plain JMP */
/* JMPZ(X,L1), L1: JMP(L2) => JMPZ(X,L2), L1: JMP(L2) */
- CHECK_JMP(target, done_jmp_optimization);
- ZEND_SET_OP_JMP_ADDR(opline, opline->op2, ZEND_OP1_JMP_ADDR(target));
+ target = ZEND_OP1_JMP_ADDR(target);
+ CHECK_LOOP(target);
} else if (target->opcode == opline->opcode &&
SAME_VAR(opline->op1, target->op1)) {
/* same opcode and same var as this opcode */
/* JMPZ(X,L1), L1: JMPZ(X,L2) => JMPZ(X,L2), L1: JMPZ(X,L2) */
- CHECK_JMP2(target, done_jmp_optimization);
- ZEND_SET_OP_JMP_ADDR(opline, opline->op2, ZEND_OP2_JMP_ADDR(target));
- } else if (target->opcode == opline->opcode + 3 &&
- SAME_VAR(opline->op1, target->op1)) {
- /* convert JMPZ(X,L1), L1: T JMPZ_EX(X,L2) to
- T = JMPZ_EX(X, L2) */
- ZEND_SET_OP_JMP_ADDR(opline, opline->op2, ZEND_OP2_JMP_ADDR(target));
- opline->opcode += 3;
- COPY_NODE(opline->result, target->result);
- break;
+ target = ZEND_OP2_JMP_ADDR(target);
+ CHECK_LOOP(target);
} else if (target->opcode == INV_COND(opline->opcode) &&
SAME_VAR(opline->op1, target->op1)) {
/* convert JMPZ(X,L1), L1: JMPNZ(X,L2) to
JMPZ(X,L1+1) */
- ZEND_SET_OP_JMP_ADDR(opline, opline->op2, target + 1);
- break;
- } else if (target->opcode == INV_COND_EX(opline->opcode) &&
+ target = target + 1;
+ } else if (target->opcode == ZEND_JMPZNZ &&
SAME_VAR(opline->op1, target->op1)) {
- /* convert JMPZ(X,L1), L1: T = JMPNZ_EX(X,L2) to
- T = JMPZ_EX(X,L1+1) */
- ZEND_SET_OP_JMP_ADDR(opline, opline->op2, target + 1);
- opline->opcode += 3;
- COPY_NODE(opline->result, target->result);
- break;
+ target = (opline->opcode == ZEND_JMPZ) ?
+ ZEND_OP2_JMP_ADDR(target) :
+ ZEND_OFFSET_TO_OPLINE(target, target->extended_value);
+ CHECK_LOOP(target);
+ } else if (target->opcode == ZEND_NOP) {
+ target = target + 1;
} else {
break;
}
+ ZEND_SET_OP_JMP_ADDR(opline, opline->op2, target);
+ }
+
+ /* convert L: JMPZ L+1 to NOP */
+ if (target == opline + 1) {
+ if (opline->op1_type == IS_CV) {
+ opline->opcode = ZEND_CHECK_VAR;
+ opline->op2.num = 0;
+ } else if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) {
+ opline->opcode = ZEND_FREE;
+ opline->op2.num = 0;
+ } else {
+ MAKE_NOP(opline);
+ }
}
break;
case ZEND_JMPZ_EX:
- case ZEND_JMPNZ_EX: {
- zend_uchar T_type = opline->result_type;
- znode_op T = opline->result;
+ case ZEND_JMPNZ_EX:
+ jmp_hitlist_count = 0;
- if (op_array->fn_flags & ZEND_ACC_HAS_FINALLY_BLOCK) {
+ target = ZEND_OP2_JMP_ADDR(opline);
+ while (1) {
+ if (target->opcode == ZEND_JMP) {
+ /* plain JMP */
+ /* JMPZ_EX(X,L1), L1: JMP(L2) => JMPZ_EX(X,L2), L1: JMP(L2) */
+ target = ZEND_OP1_JMP_ADDR(target);
+ CHECK_LOOP(target);
+ } else if (target->opcode == opline->opcode-3 &&
+ (SAME_VAR(target->op1, opline->result) ||
+ SAME_VAR(target->op1, opline->op1))) {
+ /* convert T=JMPZ_EX(X,L1), L1: JMPZ(T,L2) to
+ JMPZ_EX(X,L2) */
+ target = ZEND_OP2_JMP_ADDR(target);
+ CHECK_LOOP(target);
+ } else if (target->opcode == opline->opcode &&
+ target->result.var == opline->result.var &&
+ (SAME_VAR(target->op1, opline->result) ||
+ SAME_VAR(target->op1, opline->op1))) {
+ /* convert T=JMPZ_EX(X,L1), L1: T=JMPZ_EX(T,L2) to
+ JMPZ_EX(X,L2) */
+ target = ZEND_OP2_JMP_ADDR(target);
+ CHECK_LOOP(target);
+ } else if (target->opcode == ZEND_JMPZNZ &&
+ (SAME_VAR(target->op1, opline->result) ||
+ SAME_VAR(target->op1, opline->op1))) {
+ /* Check for JMPZNZ with same cond variable */
+ target = (opline->opcode == ZEND_JMPZ_EX) ?
+ ZEND_OP2_JMP_ADDR(target) :
+ ZEND_OFFSET_TO_OPLINE(target, target->extended_value);
+ CHECK_LOOP(target);
+ } else if (target->opcode == INV_EX_COND(opline->opcode) &&
+ (SAME_VAR(target->op1, opline->result) ||
+ SAME_VAR(target->op1, opline->op1))) {
+ /* convert T=JMPZ_EX(X,L1), L1: JMPNZ(T,L2) to
+ JMPZ_EX(X,L1+1) */
+ target = target + 1;
+ } else if (target->opcode == INV_EX_COND_EX(opline->opcode) &&
+ target->result.var == opline->result.var &&
+ (SAME_VAR(target->op1, opline->result) ||
+ SAME_VAR(target->op1, opline->op1))) {
+ /* convert T=JMPZ_EX(X,L1), L1: T=JMPNZ_EX(T,L2) to
+ JMPZ_EX(X,L1+1) */
+ target = target + 1;
+ } else if (target->opcode == ZEND_BOOL &&
+ (SAME_VAR(target->op1, opline->result) ||
+ SAME_VAR(target->op1, opline->op1))) {
+ /* convert Y = JMPZ_EX(X,L1), L1: Z = BOOL(Y) to
+ Z = JMPZ_EX(X,L1+1) */
+
+ /* NOTE: This optimization pattern is not safe, but works, */
+ /* because result of JMPZ_EX instruction */
+ /* is not used on the following path and */
+ /* should be used once on the branch path. */
+ /* */
+ /* The pattern works well only if jums processed in */
+ /* direct order, otherwise it breakes JMPZ_EX */
+ /* sequences too early. */
+ opline->result.var = target->result.var;
+ target = target + 1;
+ CHECK_LOOP(target);
+ } else if (target->opcode == ZEND_NOP) {
+ target = target + 1;
+ } else {
break;
}
+ ZEND_SET_OP_JMP_ADDR(opline, opline->op2, target);
+ }
- /* convert L: T = JMPZ_EX X,L+1 to T = BOOL(X) */
- /* convert L: T = JMPZ_EX T,L+1 to NOP */
- if (ZEND_OP2_JMP_ADDR(opline) == opline + 1) {
- if (opline->op1.var == opline->result.var) {
- MAKE_NOP(opline);
- } else {
- opline->opcode = ZEND_BOOL;
- SET_UNUSED(opline->op2);
- }
- goto done_jmp_optimization;
- }
-
- while (ZEND_OP2_JMP_ADDR(opline) < end) {
- zend_op *target = ZEND_OP2_JMP_ADDR(opline);
-
- if (target->opcode == opline->opcode-3 &&
- SAME_VAR(target->op1, T)) {
- /* convert T=JMPZ_EX(X,L1), L1: JMPZ(T,L2) to
- JMPZ_EX(X,L2) */
- CHECK_JMP2(target, continue_jmp_ex_optimization);
- ZEND_SET_OP_JMP_ADDR(opline, opline->op2, ZEND_OP2_JMP_ADDR(target));
- } else if (target->opcode == opline->opcode &&
- SAME_VAR(target->op1, T) &&
- SAME_VAR(target->result, T)) {
- /* convert T=JMPZ_EX(X,L1), L1: T=JMPZ_EX(T,L2) to
- JMPZ_EX(X,L2) */
- CHECK_JMP2(target, continue_jmp_ex_optimization);
- ZEND_SET_OP_JMP_ADDR(opline, opline->op2, ZEND_OP2_JMP_ADDR(target));
- } else if (target->opcode == ZEND_JMPZNZ &&
- SAME_VAR(target->op1, T)) {
- /* Check for JMPZNZ with same cond variable */
- zend_op *new_target;
-
- CHECK_JMP2(target, continue_jmp_ex_optimization);
- if (opline->opcode == ZEND_JMPZ_EX) {
- new_target = ZEND_OP2_JMP_ADDR(target);
- } else {
- /* JMPNZ_EX */
- new_target = ZEND_OFFSET_TO_OPLINE(target, target->extended_value);
- }
- ZEND_SET_OP_JMP_ADDR(opline, opline->op2, new_target);
- } else if ((target->opcode == INV_EX_COND_EX(opline->opcode) ||
- target->opcode == INV_EX_COND(opline->opcode)) &&
- SAME_VAR(opline->op1, target->op1)) {
- /* convert JMPZ_EX(X,L1), L1: JMPNZ_EX(X,L2) to
- JMPZ_EX(X,L1+1) */
- ZEND_SET_OP_JMP_ADDR(opline, opline->op2, target + 1);
- break;
- } else if (target->opcode == INV_EX_COND(opline->opcode) &&
- SAME_VAR(target->op1, T)) {
- /* convert T=JMPZ_EX(X,L1), L1: JMPNZ(T,L2) to
- JMPZ_EX(X,L1+1) */
- ZEND_SET_OP_JMP_ADDR(opline, opline->op2, target + 1);
- break;
- } else if (target->opcode == INV_EX_COND_EX(opline->opcode) &&
- SAME_VAR(target->op1, T) &&
- SAME_VAR(target->result, T)) {
- /* convert T=JMPZ_EX(X,L1), L1: T=JMPNZ_EX(T,L2) to
- JMPZ_EX(X,L1+1) */
- ZEND_SET_OP_JMP_ADDR(opline, opline->op2, target + 1);
- break;
- } else if (target->opcode == ZEND_BOOL &&
- SAME_VAR(opline->result, target->op1)) {
- /* convert Y = JMPZ_EX(X,L1), L1: Z = BOOL(Y) to
- Z = JMPZ_EX(X,L1+1) */
- opline->result.var = target->result.var;
- ZEND_SET_OP_JMP_ADDR(opline, opline->op2, target + 1);
- break;
- } else {
- break;
- }
- } /* while */
-continue_jmp_ex_optimization:
- break;
-#if 0
- /* If Ti = JMPZ_EX(X, L) and Ti is not used, convert to JMPZ(X, L) */
- {
- zend_op *op;
- for(op = opline+1; op<end; op++) {
- if(op->result_type == IS_TMP_VAR &&
- op->result.var == opline->result.var) {
- break; /* can pass to part 2 */
- }
-
- if(op->opcode == ZEND_JMP ||
- op->opcode == ZEND_JMPZ ||
- op->opcode == ZEND_JMPZ_EX ||
- op->opcode == ZEND_JMPNZ ||
- op->opcode == ZEND_JMPNZ_EX ||
- op->opcode == ZEND_JMPZNZ ||
- op->opcode == ZEND_CASE ||
- op->opcode == ZEND_RETURN ||
- op->opcode == ZEND_RETURN_BY_REF ||
- op->opcode == ZEND_FAST_RET ||
- op->opcode == ZEND_FE_FETCH_R ||
- op->opcode == ZEND_FE_FETCH_RW ||
- op->opcode == ZEND_EXIT) {
- break;
- }
-
- if(op->op1_type == IS_TMP_VAR &&
- op->op1.var == opline->result.var) {
- goto done_jmp_optimization;
- }
-
- if(op->op2_type == IS_TMP_VAR &&
- op->op2.var == opline->result.var) {
- goto done_jmp_optimization;
- }
- } /* for */
-
- for(op = &op_array->opcodes[opline->op2.opline_num]; op<end; op++) {
-
- if(op->result_type == IS_TMP_VAR &&
- op->result.var == opline->result.var) {
- break; /* can pass to optimization */
- }
-
- if(op->opcode == ZEND_JMP ||
- op->opcode == ZEND_JMPZ ||
- op->opcode == ZEND_JMPZ_EX ||
- op->opcode == ZEND_JMPNZ ||
- op->opcode == ZEND_JMPNZ_EX ||
- op->opcode == ZEND_JMPZNZ ||
- op->opcode == ZEND_CASE ||
- op->opcode == ZEND_RETURN ||
- op->opcode == ZEND_RETURN_BY_REF ||
- op->opcode == ZEND_FAST_RET ||
- op->opcode == ZEND_FE_FETCH_R ||
- op->opcode == ZEND_FE_FETCH_RW ||
- op->opcode == ZEND_EXIT) {
- break;
- }
-
- if(op->op1_type == IS_TMP_VAR &&
- op->op1.var == opline->result.var) {
- goto done_jmp_optimization;
- }
-
- if(op->op2_type == IS_TMP_VAR &&
- op->op2.var == opline->result.var) {
- goto done_jmp_optimization;
- }
- }
-
- opline->opcode = opline->opcode-3; /* JMP_EX -> JMP */
- SET_UNUSED(opline->result);
- break;
- }
-#endif
+ /* convert L: T = JMPZ_EX X,L+1 to T = BOOL(X) */
+ if (target == opline + 1) {
+ opline->opcode = ZEND_BOOL;
+ opline->op2.num = 0;
}
break;
case ZEND_JMPZNZ:
- if (op_array->fn_flags & ZEND_ACC_HAS_FINALLY_BLOCK) {
- break;
- }
-
- /* JMPZNZ(X,L1,L2), L1: JMP(L3) => JMPZNZ(X,L3,L2), L1: JMP(L3) */
- while (ZEND_OP2_JMP_ADDR(opline) < end
- && ZEND_OP2_JMP_ADDR(opline)->opcode == ZEND_JMP) {
- zend_op *target = ZEND_OP2_JMP_ADDR(opline);
- CHECK_JMP(target, continue_jmpznz_optimization);
- ZEND_SET_OP_JMP_ADDR(opline, opline->op2, ZEND_OP1_JMP_ADDR(target));
- }
-continue_jmpznz_optimization:
- /* JMPZNZ(X,L1,L2), L2: JMP(L3) => JMPZNZ(X,L1,L3), L2: JMP(L3) */
- while (ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value) < end
- && ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value)->opcode == ZEND_JMP) {
- zend_op *target = ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value);
- CHECK_JMP(target, done_jmp_optimization);
- opline->extended_value = ZEND_OPLINE_TO_OFFSET(opline, ZEND_OP1_JMP_ADDR(target));
+optimize_jmpznz:
+ jmp_hitlist_count = 0;
+ target = ZEND_OP2_JMP_ADDR(opline);
+ while (1) {
+ if (target->opcode == ZEND_JMP) {
+ /* JMPZNZ(X,L1,L2), L1: JMP(L3) => JMPZNZ(X,L3,L2), L1: JMP(L3) */
+ target = ZEND_OP1_JMP_ADDR(target);
+ CHECK_LOOP(target);
+ } else if ((target->opcode == ZEND_JMPZ || target->opcode == ZEND_JMPZNZ) &&
+ SAME_VAR(target->op1, opline->op1)) {
+ /* JMPZNZ(X, L1, L2), L1: JMPZ(X, L3) -> JMPZNZ(X, L3, L2) */
+ target = ZEND_OP2_JMP_ADDR(target);
+ CHECK_LOOP(target);
+ } else if (target->opcode == ZEND_JMPNZ &&
+ SAME_VAR(target->op1, opline->op1)) {
+ /* JMPZNZ(X, L1, L2), L1: X = JMPNZ(X, L3) -> JMPZNZ(X, L1+1, L2) */
+ target = target + 1;
+ } else if (target->opcode == ZEND_NOP) {
+ target = target + 1;
+ } else {
+ break;
+ }
+ ZEND_SET_OP_JMP_ADDR(opline, opline->op2, target);
}
- break;
-
- case ZEND_POST_INC_OBJ:
- case ZEND_POST_DEC_OBJ:
- case ZEND_POST_INC:
- case ZEND_POST_DEC: {
- /* POST_INC, FREE => PRE_INC */
- zend_op *next_op = opline + 1;
- if (next_op >= end) {
+ jmp_hitlist_count = 0;
+ target = ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value);
+ while (1) {
+ if (target->opcode == ZEND_JMP) {
+ /* JMPZNZ(X,L1,L2), L2: JMP(L3) => JMPZNZ(X,L1,L3), L2: JMP(L3) */
+ target = ZEND_OP1_JMP_ADDR(target);
+ CHECK_LOOP(target);
+ } else if (target->opcode == ZEND_JMPNZ &&
+ SAME_VAR(target->op1, opline->op1)) {
+ /* JMPZNZ(X, L1, L2), L1: X = JMPNZ(X, L3) -> JMPZNZ(X, L1+1, L2) */
+ target = ZEND_OP2_JMP_ADDR(target);
+ CHECK_LOOP(target);
+ } else if (target->opcode == ZEND_JMPZ &&
+ SAME_VAR(target->op1, opline->op1)) {
+ /* JMPZNZ(X, L1, L2), L1: JMPZ(X, L3) -> JMPZNZ(X, L3, L2) */
+ target = target + 1;
+ } else if (target->opcode == ZEND_JMPZNZ &&
+ SAME_VAR(target->op1, opline->op1)) {
+ /* JMPZNZ(X, L1, L2), L1: JMPZ(X, L3) -> JMPZNZ(X, L3, L2) */
+ target = ZEND_OFFSET_TO_OPLINE(target, target->extended_value);
+ CHECK_LOOP(target);
+ } else if (target->opcode == ZEND_NOP) {
+ target = target + 1;
+ } else {
break;
}
- if (next_op->opcode == ZEND_FREE &&
- next_op->op1.var == opline->result.var) {
- MAKE_NOP(next_op);
- opline->opcode -= 2;
- opline->result_type = IS_UNUSED;
- }
+ opline->extended_value = ZEND_OPLINE_TO_OFFSET(opline, target);
+ }
+
+ if (ZEND_OP2_JMP_ADDR(opline) == target &&
+ !(opline->op1_type & (IS_VAR|IS_TMP_VAR))) {
+ /* JMPZNZ(?,L,L) -> JMP(L) */
+ opline->opcode = ZEND_JMP;
+ ZEND_SET_OP_JMP_ADDR(opline, opline->op1, target);
+ SET_UNUSED(opline->op1);
+ SET_UNUSED(opline->op2);
+ opline->extended_value = 0;
}
+ /* Don't convert JMPZNZ back to JMPZ/JMPNZ, because the
+ following JMP is not removed yet. */
break;
}
-done_jmp_optimization:
opline++;
- opline_num++;
}
free_alloca(jmp_hitlist, use_heap);
}
diff --git a/ext/opcache/Optimizer/sccp.c b/ext/opcache/Optimizer/sccp.c
index 6f8de3d43f..57ae48b021 100644
--- a/ext/opcache/Optimizer/sccp.c
+++ b/ext/opcache/Optimizer/sccp.c
@@ -740,13 +740,12 @@ static inline int ct_eval_in_array(zval *result, uint32_t extended_value, zval *
res = zend_hash_exists(ht, ZSTR_EMPTY_ALLOC());
} else {
zend_string *key;
- zval key_tmp, result_tmp;
+ zval key_tmp;
res = 0;
ZEND_HASH_FOREACH_STR_KEY(ht, key) {
ZVAL_STR(&key_tmp, key);
- compare_function(&result_tmp, op1, &key_tmp);
- if (Z_LVAL(result_tmp) == 0) {
+ if (zend_compare(op1, &key_tmp) == 0) {
res = 1;
break;
}
@@ -892,8 +891,7 @@ static inline int ct_eval_func_call(
} else if (zend_string_equals_literal(name, "strpos")) {
if (Z_TYPE_P(args[0]) != IS_STRING
|| Z_TYPE_P(args[1]) != IS_STRING
- || !Z_STRLEN_P(args[1])
- || (CG(compiler_options) & ZEND_COMPILE_NO_BUILTIN_STRLEN)) {
+ || !Z_STRLEN_P(args[1])) {
return FAILURE;
}
/* pass */
@@ -972,8 +970,7 @@ static inline int ct_eval_func_call(
/* pass */
} else if (zend_string_equals_literal(name, "substr")) {
if (Z_TYPE_P(args[0]) != IS_STRING
- || Z_TYPE_P(args[1]) != IS_LONG
- || (CG(compiler_options) & ZEND_COMPILE_NO_BUILTIN_STRLEN)) {
+ || Z_TYPE_P(args[1]) != IS_LONG) {
return FAILURE;
}
/* pass */
@@ -1017,8 +1014,7 @@ static inline int ct_eval_func_call(
} else if (zend_string_equals_literal(name, "substr")) {
if (Z_TYPE_P(args[0]) != IS_STRING
|| Z_TYPE_P(args[1]) != IS_LONG
- || Z_TYPE_P(args[2]) != IS_LONG
- || (CG(compiler_options) & ZEND_COMPILE_NO_BUILTIN_STRLEN)) {
+ || Z_TYPE_P(args[2]) != IS_LONG) {
return FAILURE;
}
/* pass */
diff --git a/ext/opcache/Optimizer/ssa_integrity.c b/ext/opcache/Optimizer/ssa_integrity.c
index ede40be59a..4f042cae74 100644
--- a/ext/opcache/Optimizer/ssa_integrity.c
+++ b/ext/opcache/Optimizer/ssa_integrity.c
@@ -87,7 +87,7 @@ static inline zend_bool is_in_successors(zend_basic_block *block, int check) {
}
static inline zend_bool is_var_type(zend_uchar type) {
- return type == IS_CV || type == IS_VAR || type == IS_TMP_VAR;
+ return (type & (IS_CV|IS_VAR|IS_TMP_VAR)) != 0;
}
#define FAIL(...) do { \
diff --git a/ext/opcache/Optimizer/zend_call_graph.c b/ext/opcache/Optimizer/zend_call_graph.c
index 8d677c1b86..28b20d10b8 100644
--- a/ext/opcache/Optimizer/zend_call_graph.c
+++ b/ext/opcache/Optimizer/zend_call_graph.c
@@ -103,7 +103,7 @@ int zend_analyze_calls(zend_arena **arena, zend_script *script, uint32_t build_f
case ZEND_INIT_STATIC_METHOD_CALL:
call_stack[call] = call_info;
func = zend_optimizer_get_called_func(
- script, op_array, opline, (build_flags & ZEND_RT_CONSTANTS) != 0);
+ script, op_array, opline);
if (func) {
call_info = zend_arena_calloc(arena, 1, sizeof(zend_call_info) + (sizeof(zend_send_arg_info) * ((int)opline->extended_value - 1)));
call_info->caller_op_array = op_array;
@@ -250,10 +250,8 @@ static void zend_sort_op_arrays(zend_call_graph *call_graph)
// TODO: perform topological sort of cyclic call graph
}
-int zend_build_call_graph(zend_arena **arena, zend_script *script, uint32_t build_flags, zend_call_graph *call_graph) /* {{{ */
+int zend_build_call_graph(zend_arena **arena, zend_script *script, zend_call_graph *call_graph) /* {{{ */
{
- int i;
-
call_graph->op_arrays_count = 0;
if (zend_foreach_op_array(call_graph, script, zend_op_array_calc) != SUCCESS) {
return FAILURE;
@@ -264,13 +262,20 @@ int zend_build_call_graph(zend_arena **arena, zend_script *script, uint32_t buil
if (zend_foreach_op_array(call_graph, script, zend_op_array_collect) != SUCCESS) {
return FAILURE;
}
+
+ return SUCCESS;
+}
+/* }}} */
+
+void zend_analyze_call_graph(zend_arena **arena, zend_script *script, zend_call_graph *call_graph) /* {{{ */
+{
+ int i;
+
for (i = 0; i < call_graph->op_arrays_count; i++) {
- zend_analyze_calls(arena, script, build_flags, call_graph->op_arrays[i], call_graph->func_infos + i);
+ zend_analyze_calls(arena, script, 0, call_graph->op_arrays[i], call_graph->func_infos + i);
}
zend_analyze_recursion(call_graph);
zend_sort_op_arrays(call_graph);
-
- return SUCCESS;
}
/* }}} */
diff --git a/ext/opcache/Optimizer/zend_call_graph.h b/ext/opcache/Optimizer/zend_call_graph.h
index 033c675b63..8d2b866fd0 100644
--- a/ext/opcache/Optimizer/zend_call_graph.h
+++ b/ext/opcache/Optimizer/zend_call_graph.h
@@ -69,7 +69,8 @@ typedef struct _zend_call_graph {
BEGIN_EXTERN_C()
-int zend_build_call_graph(zend_arena **arena, zend_script *script, uint32_t build_flags, zend_call_graph *call_graph);
+int zend_build_call_graph(zend_arena **arena, zend_script *script, zend_call_graph *call_graph);
+void zend_analyze_call_graph(zend_arena **arena, zend_script *script, zend_call_graph *call_graph);
zend_call_info **zend_build_call_map(zend_arena **arena, zend_func_info *info, zend_op_array *op_array);
int zend_analyze_calls(zend_arena **arena, zend_script *script, uint32_t build_flags, zend_op_array *op_array, zend_func_info *func_info);
diff --git a/ext/opcache/Optimizer/zend_cfg.h b/ext/opcache/Optimizer/zend_cfg.h
index 7d6ef25eee..ec7a10462c 100644
--- a/ext/opcache/Optimizer/zend_cfg.h
+++ b/ext/opcache/Optimizer/zend_cfg.h
@@ -92,7 +92,6 @@ typedef struct _zend_cfg {
} zend_cfg;
/* Build Flags */
-#define ZEND_RT_CONSTANTS (1U<<31)
#define ZEND_CFG_STACKLESS (1<<30)
#define ZEND_SSA_DEBUG_LIVENESS (1<<29)
#define ZEND_SSA_DEBUG_PHI_PLACEMENT (1<<28)
@@ -102,15 +101,15 @@ typedef struct _zend_cfg {
#define ZEND_CALL_TREE (1<<23)
#define ZEND_SSA_USE_CV_RESULTS (1<<22)
-#define CRT_CONSTANT_EX(op_array, opline, node, rt_constants) \
- ((rt_constants) ? \
+#define CRT_CONSTANT_EX(op_array, opline, node) \
+ (((op_array)->fn_flags & ZEND_ACC_DONE_PASS_TWO) ? \
RT_CONSTANT(opline, (node)) \
: \
CT_CONSTANT_EX(op_array, (node).constant) \
)
#define CRT_CONSTANT(node) \
- CRT_CONSTANT_EX(op_array, opline, node, (build_flags & ZEND_RT_CONSTANTS))
+ CRT_CONSTANT_EX(op_array, opline, node)
#define RETURN_VALUE_USED(opline) \
((opline)->result_type != IS_UNUSED)
diff --git a/ext/opcache/Optimizer/zend_dfg.c b/ext/opcache/Optimizer/zend_dfg.c
index e995b673b7..3bb76fb05c 100644
--- a/ext/opcache/Optimizer/zend_dfg.c
+++ b/ext/opcache/Optimizer/zend_dfg.c
@@ -123,10 +123,6 @@ int zend_build_dfg(const zend_op_array *op_array, const zend_cfg *cfg, zend_dfg
case ZEND_FETCH_DIM_RW:
case ZEND_FETCH_DIM_FUNC_ARG:
case ZEND_FETCH_DIM_UNSET:
- case ZEND_FETCH_OBJ_W:
- case ZEND_FETCH_OBJ_RW:
- case ZEND_FETCH_OBJ_FUNC_ARG:
- case ZEND_FETCH_OBJ_UNSET:
case ZEND_FETCH_LIST_W:
case ZEND_VERIFY_RETURN_TYPE:
case ZEND_PRE_INC_OBJ:
diff --git a/ext/opcache/Optimizer/zend_dump.c b/ext/opcache/Optimizer/zend_dump.c
index d6ef63415a..68b3d4a99f 100644
--- a/ext/opcache/Optimizer/zend_dump.c
+++ b/ext/opcache/Optimizer/zend_dump.c
@@ -127,11 +127,8 @@ static void zend_dump_unused_op(const zend_op *opline, znode_op op, uint32_t fla
} else if (ZEND_VM_OP_CONSTRUCTOR == (flags & ZEND_VM_OP_MASK)) {
fprintf(stderr, " CONSTRUCTOR");
} else if (ZEND_VM_OP_CONST_FETCH == (flags & ZEND_VM_OP_MASK)) {
- if (op.num & IS_CONSTANT_UNQUALIFIED) {
- fprintf(stderr, " (unqualified)");
- }
- if (op.num & IS_CONSTANT_IN_NAMESPACE) {
- fprintf(stderr, " (in-namespace)");
+ if (op.num & IS_CONSTANT_UNQUALIFIED_IN_NAMESPACE) {
+ fprintf(stderr, " (unqualified-in-namespace)");
}
}
}
@@ -142,7 +139,7 @@ void zend_dump_var(const zend_op_array *op_array, zend_uchar var_type, int var_n
fprintf(stderr, "CV%d($%s)", var_num, op_array->vars[var_num]->val);
} else if (var_type == IS_VAR) {
fprintf(stderr, "V%d", var_num);
- } else if (var_type == IS_TMP_VAR) {
+ } else if ((var_type & (IS_VAR|IS_TMP_VAR)) == IS_TMP_VAR) {
fprintf(stderr, "T%d", var_num);
} else {
fprintf(stderr, "X%d", var_num);
@@ -314,10 +311,6 @@ static void zend_dump_type_info(uint32_t info, zend_class_entry *ce, int is_inst
fprintf(stderr, "resource");
}
}
- if (info & MAY_BE_ERROR) {
- if (first) first = 0; else fprintf(stderr, ", ");
- fprintf(stderr, "error");
- }
//TODO: this is useful only for JIT???
if (info & MAY_BE_IN_REG) {
if (first) first = 0; else fprintf(stderr, ", ");
@@ -581,20 +574,18 @@ static void zend_dump_op(const zend_op_array *op_array, const zend_basic_block *
fprintf(stderr, " (ref)");
}
}
- if ((ZEND_VM_EXT_DIM_OBJ_WRITE|ZEND_VM_EXT_FETCH_REF) & flags) {
+ if ((ZEND_VM_EXT_DIM_WRITE|ZEND_VM_EXT_FETCH_REF) & flags) {
uint32_t obj_flags = opline->extended_value & ZEND_FETCH_OBJ_FLAGS;
if (obj_flags == ZEND_FETCH_REF) {
fprintf(stderr, " (ref)");
} else if (obj_flags == ZEND_FETCH_DIM_WRITE) {
fprintf(stderr, " (dim write)");
- } else if (obj_flags == ZEND_FETCH_OBJ_WRITE) {
- fprintf(stderr, " (obj write)");
}
}
}
if (opline->op1_type == IS_CONST) {
- zend_dump_const(CRT_CONSTANT_EX(op_array, opline, opline->op1, (dump_flags & ZEND_DUMP_RT_CONSTANTS)));
+ zend_dump_const(CRT_CONSTANT(opline->op1));
} else if (opline->op1_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
if (ssa && ssa->ops) {
int ssa_var_num = ssa->ops[opline - op_array->opcodes].op1_use;
@@ -630,7 +621,7 @@ static void zend_dump_op(const zend_op_array *op_array, const zend_basic_block *
}
if (opline->op2_type == IS_CONST) {
- zval *op = CRT_CONSTANT_EX(op_array, opline, opline->op2, (dump_flags & ZEND_DUMP_RT_CONSTANTS));
+ zval *op = CRT_CONSTANT(opline->op2);
if (opline->opcode == ZEND_SWITCH_LONG || opline->opcode == ZEND_SWITCH_STRING) {
HashTable *jumptable = Z_ARRVAL_P(op);
zend_string *key;
@@ -696,7 +687,13 @@ static void zend_dump_op(const zend_op_array *op_array, const zend_basic_block *
}
}
if (opline->result_type == IS_CONST) {
- zend_dump_const(CRT_CONSTANT_EX(op_array, opline, opline->result, (dump_flags & ZEND_DUMP_RT_CONSTANTS)));
+ zend_dump_const(CRT_CONSTANT(opline->result));
+#if 0
+ } else if (opline->result_type & IS_SMART_BRANCH_JMPZ) {
+ fprintf(stderr, " jmpz");
+ } else if (opline->result_type & IS_SMART_BRANCH_JMPNZ) {
+ fprintf(stderr, " jmpnz");
+#endif
} else if (ssa && ssa->ops && ssa->ops[opline - op_array->opcodes].result_use >= 0) {
if (opline->result_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
if (ssa && ssa->ops) {
@@ -729,6 +726,9 @@ static void zend_dump_block_info(const zend_cfg *cfg, int n, uint32_t dump_flags
if (b->flags & ZEND_BB_START) {
fprintf(stderr, " start");
}
+ if (b->flags & ZEND_BB_RECV_ENTRY) {
+ fprintf(stderr, " recv");
+ }
if (b->flags & ZEND_BB_FOLLOW) {
fprintf(stderr, " follow");
}
diff --git a/ext/opcache/Optimizer/zend_func_info.c b/ext/opcache/Optimizer/zend_func_info.c
index d9ff58e75e..96fe6594f9 100644
--- a/ext/opcache/Optimizer/zend_func_info.c
+++ b/ext/opcache/Optimizer/zend_func_info.c
@@ -39,66 +39,19 @@ typedef struct _func_info_t {
info_func_t info_func;
} func_info_t;
-/* MSVC defines its own IN macro, undefine it here */
-#undef IN
-
#define F0(name, info) \
- {name, sizeof(name)-1, (FUNC_MAY_WARN | (info)), NULL}
+ {name, sizeof(name)-1, (info), NULL}
#define F1(name, info) \
- {name, sizeof(name)-1, (FUNC_MAY_WARN | MAY_BE_RC1 | (info)), NULL}
+ {name, sizeof(name)-1, (MAY_BE_RC1 | (info)), NULL}
#define FN(name, info) \
- {name, sizeof(name)-1, (FUNC_MAY_WARN | MAY_BE_RC1 | MAY_BE_RCN | (info)), NULL}
+ {name, sizeof(name)-1, (MAY_BE_RC1 | MAY_BE_RCN | (info)), NULL}
#define FR(name, info) \
- {name, sizeof(name)-1, (FUNC_MAY_WARN | MAY_BE_REF | (info)), NULL}
+ {name, sizeof(name)-1, (MAY_BE_REF | (info)), NULL}
#define FX(name, info) \
- {name, sizeof(name)-1, (FUNC_MAY_WARN | MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_REF | (info)), NULL}
-#define I0(name, info) \
- {name, sizeof(name)-1, (info), NULL}
-#define I1(name, info) \
- {name, sizeof(name)-1, (MAY_BE_RC1 | (info)), NULL}
-#define IN(name, info) \
- {name, sizeof(name)-1, (MAY_BE_RC1 | MAY_BE_RCN | (info)), NULL}
+ {name, sizeof(name)-1, (MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_REF | (info)), NULL}
#define FC(name, callback) \
{name, sizeof(name)-1, 0, callback}
-static uint32_t zend_strlen_info(const zend_call_info *call_info, const zend_ssa *ssa)
-{
- if (call_info->num_args == 1) {
- uint32_t tmp = 0;
- if (call_info->arg_info[0].opline) {
- uint32_t arg_info = _ssa_op1_info(call_info->caller_op_array, ssa, call_info->arg_info[0].opline);
-
- if (arg_info & (MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE|MAY_BE_STRING|MAY_BE_OBJECT)) {
- tmp |= MAY_BE_LONG;
- }
- if (arg_info & (MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
- /* warning, and returns NULL */
- tmp |= FUNC_MAY_WARN | MAY_BE_NULL;
- }
- } else {
- tmp |= MAY_BE_LONG | FUNC_MAY_WARN | MAY_BE_NULL;
- }
- return tmp;
- } else if (call_info->num_args != -1) {
- /* warning, and returns NULL */
- return FUNC_MAY_WARN | MAY_BE_NULL;
- } else {
- return MAY_BE_LONG | FUNC_MAY_WARN | MAY_BE_NULL;
- }
-}
-
-static uint32_t zend_dechex_info(const zend_call_info *call_info, const zend_ssa *ssa)
-{
- if (call_info->num_args == 1) {
- return MAY_BE_RC1 | MAY_BE_STRING;
- } else if (call_info->num_args != -1) {
- /* warning, and returns NULL */
- return FUNC_MAY_WARN | MAY_BE_NULL;
- } else {
- return FUNC_MAY_WARN | MAY_BE_RC1 | MAY_BE_STRING | MAY_BE_NULL;
- }
-}
-
static uint32_t zend_range_info(const zend_call_info *call_info, const zend_ssa *ssa)
{
if (call_info->num_args == 2 || call_info->num_args == 3) {
@@ -106,7 +59,7 @@ static uint32_t zend_range_info(const zend_call_info *call_info, const zend_ssa
uint32_t t1 = _ssa_op1_info(call_info->caller_op_array, ssa, call_info->arg_info[0].opline);
uint32_t t2 = _ssa_op1_info(call_info->caller_op_array, ssa, call_info->arg_info[1].opline);
uint32_t t3 = 0;
- uint32_t tmp = FUNC_MAY_WARN | MAY_BE_RC1 | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG;
+ uint32_t tmp = MAY_BE_RC1 | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG;
if (call_info->num_args == 3) {
t3 = _ssa_op1_info(call_info->caller_op_array, ssa, call_info->arg_info[2].opline);
@@ -127,87 +80,7 @@ static uint32_t zend_range_info(const zend_call_info *call_info, const zend_ssa
return tmp;
} else {
/* may warning, and return FALSE */
- return FUNC_MAY_WARN | MAY_BE_RC1 | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_DOUBLE | MAY_BE_ARRAY_OF_STRING;
- }
-}
-
-static uint32_t zend_is_type_info(const zend_call_info *call_info, const zend_ssa *ssa)
-{
- if (call_info->num_args == 1) {
- return MAY_BE_FALSE | MAY_BE_TRUE;
- } else {
- return MAY_BE_FALSE | MAY_BE_TRUE | FUNC_MAY_WARN;
- }
-}
-
-static uint32_t zend_l_ss_info(const zend_call_info *call_info, const zend_ssa *ssa)
-{
- if (call_info->num_args == 2) {
-
- uint32_t arg1_info = _ssa_op1_info(call_info->caller_op_array, ssa, call_info->arg_info[0].opline);
- uint32_t arg2_info = _ssa_op1_info(call_info->caller_op_array, ssa, call_info->arg_info[1].opline);
- uint32_t tmp = 0;
-
- if ((arg1_info & (MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE|MAY_BE_STRING|MAY_BE_OBJECT)) &&
- (arg2_info & (MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE|MAY_BE_STRING|MAY_BE_OBJECT))) {
- tmp |= MAY_BE_LONG;
- }
- if ((arg1_info & (MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
- (arg2_info & (MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
- /* warning, and returns NULL */
- tmp |= FUNC_MAY_WARN | MAY_BE_NULL;
- }
- return tmp;
- } else {
- /* warning, and returns NULL */
- return FUNC_MAY_WARN | MAY_BE_NULL | MAY_BE_LONG;
- }
-}
-
-static uint32_t zend_lb_ssn_info(const zend_call_info *call_info, const zend_ssa *ssa)
-{
- if (call_info->num_args == 3) {
- uint32_t arg1_info = _ssa_op1_info(call_info->caller_op_array, ssa, call_info->arg_info[0].opline);
- uint32_t arg2_info = _ssa_op1_info(call_info->caller_op_array, ssa, call_info->arg_info[1].opline);
- uint32_t arg3_info = _ssa_op1_info(call_info->caller_op_array, ssa, call_info->arg_info[2].opline);
- uint32_t tmp = 0;
-
- if ((arg1_info & (MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE|MAY_BE_STRING|MAY_BE_OBJECT)) &&
- (arg2_info & (MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE|MAY_BE_STRING|MAY_BE_OBJECT)) &&
- (arg3_info & (MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE|MAY_BE_STRING|MAY_BE_OBJECT))) {
- tmp |= MAY_BE_LONG | MAY_BE_FALSE;
- }
- if ((arg1_info & (MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
- (arg2_info & (MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
- (arg3_info & (MAY_BE_STRING|MAY_BE_RESOURCE|MAY_BE_ARRAY|MAY_BE_OBJECT))) {
- /* warning, and returns NULL */
- tmp |= FUNC_MAY_WARN | MAY_BE_NULL;
- }
- return tmp;
- } else {
- /* warning, and returns NULL */
- return FUNC_MAY_WARN | MAY_BE_NULL | MAY_BE_LONG;
- }
-}
-
-static uint32_t zend_b_s_info(const zend_call_info *call_info, const zend_ssa *ssa)
-{
- if (call_info->num_args == 1) {
-
- uint32_t arg1_info = _ssa_op1_info(call_info->caller_op_array, ssa, call_info->arg_info[0].opline);
- uint32_t tmp = 0;
-
- if (arg1_info & (MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE|MAY_BE_STRING|MAY_BE_OBJECT)) {
- tmp |= MAY_BE_FALSE | MAY_BE_TRUE;
- }
- if (arg1_info & (MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
- /* warning, and returns NULL */
- tmp |= FUNC_MAY_WARN | MAY_BE_NULL;
- }
- return tmp;
- } else {
- /* warning, and returns NULL */
- return FUNC_MAY_WARN | MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE;
+ return MAY_BE_RC1 | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_DOUBLE | MAY_BE_ARRAY_OF_STRING;
}
}
@@ -215,191 +88,158 @@ static uint32_t zend_b_s_info(const zend_call_info *call_info, const zend_ssa *s
static const func_info_t func_infos[] = {
/* zend */
- I1("zend_version", MAY_BE_STRING),
- I0("gc_collect_cycles", MAY_BE_LONG),
- I0("gc_enabled", MAY_BE_FALSE | MAY_BE_TRUE),
- F0("gc_enable", MAY_BE_NULL),
- F0("gc_disable", MAY_BE_NULL),
- F0("func_num_args", MAY_BE_LONG),
+ F1("zend_version", MAY_BE_STRING),
FN("func_get_arg", UNKNOWN_INFO),
F1("func_get_args", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_ANY),
- FC("strlen", zend_strlen_info),
- FC("strcmp", zend_l_ss_info),
- FC("strncmp", zend_lb_ssn_info),
- FC("strcasecmp", zend_l_ss_info),
- FC("strncasecmp", zend_lb_ssn_info),
- F1("each", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_KEY_ANY),
- F0("error_reporting", MAY_BE_NULL | MAY_BE_LONG),
- F0("define", MAY_BE_FALSE | MAY_BE_TRUE | MAY_BE_NULL), // TODO: inline
- FC("defined", zend_b_s_info), // TODO: inline
+ F0("strncmp", MAY_BE_FALSE | MAY_BE_LONG),
+ F0("strncasecmp", MAY_BE_FALSE | MAY_BE_LONG),
FN("get_class", MAY_BE_FALSE | MAY_BE_STRING),
FN("get_called_class", MAY_BE_FALSE | MAY_BE_STRING),
- FN("get_parent_class", MAY_BE_FALSE | MAY_BE_STRING | MAY_BE_NULL),
- F0("is_subclass_of", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE), // TODO: inline
- F0("is_a", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE), // TODO: inline
- F1("get_class_vars", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF),
- FN("get_object_vars", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF),
- FN("get_mangled_object_vars", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF),
- F1("get_class_methods", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
- F0("method_exists", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("property_exists", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("class_exists", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("interface_exists", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("trait_exists", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- FC("function_exists", zend_b_s_info), // TODO: inline
- F0("class_alias", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- I1("get_included_files", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
- F0("trigger_error", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("user_error", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
+ FN("get_parent_class", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("get_class_vars", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF),
+ FN("get_object_vars", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF),
+ FN("get_mangled_object_vars", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF),
+ F1("get_class_methods", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
+ F1("get_included_files", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
FN("set_error_handler", MAY_BE_NULL | MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_OBJECT | MAY_BE_OBJECT),
- I0("restore_error_handler", MAY_BE_TRUE),
- I0("restore_exception_handler", MAY_BE_TRUE),
- I1("get_declared_traits", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
- I1("get_declared_classes", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
- I1("get_declared_interfaces", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
- F1("get_defined_functions", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ARRAY),
- I1("get_defined_vars", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF),
- FN("create_function", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE | MAY_BE_STRING),
- F1("get_resource_type", MAY_BE_NULL | MAY_BE_STRING),
- F1("get_defined_constants", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_NULL | MAY_BE_ARRAY_OF_FALSE | MAY_BE_ARRAY_OF_TRUE | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_DOUBLE | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_RESOURCE | MAY_BE_ARRAY_OF_ARRAY),
- F0("debug_print_backtrace", MAY_BE_NULL),
- F1("debug_backtrace", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_ARRAY),
- F1("get_loaded_extensions", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
- FC("extension_loaded", zend_b_s_info),
- F1("get_extension_funcs", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
+ F0("restore_error_handler", MAY_BE_TRUE),
+ F0("restore_exception_handler", MAY_BE_TRUE),
+ F1("get_declared_traits", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
+ F1("get_declared_classes", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
+ F1("get_declared_interfaces", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
+ F1("get_defined_functions", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ARRAY),
+ F1("get_defined_vars", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF),
+ F1("get_resource_type", MAY_BE_STRING),
+ F1("get_defined_constants", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_NULL | MAY_BE_ARRAY_OF_FALSE | MAY_BE_ARRAY_OF_TRUE | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_DOUBLE | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_RESOURCE | MAY_BE_ARRAY_OF_ARRAY),
+ F1("debug_backtrace", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_ARRAY),
+ F1("get_loaded_extensions", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
+ F1("get_extension_funcs", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
/* ext/standard */
FN("constant", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE | MAY_BE_LONG | MAY_BE_DOUBLE | MAY_BE_STRING | MAY_BE_RESOURCE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY),
- F1("bin2hex", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("hex2bin", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
+ F1("bin2hex", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("hex2bin", MAY_BE_FALSE | MAY_BE_STRING),
F0("sleep", MAY_BE_FALSE | MAY_BE_LONG),
F0("usleep", MAY_BE_NULL | MAY_BE_FALSE),
#if HAVE_NANOSLEEP
- F0("time_nanosleep", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_LONG),
- F0("time_sleep_until", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
+ F1("time_nanosleep", MAY_BE_FALSE | MAY_BE_TRUE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_LONG),
+ F0("time_sleep_until", MAY_BE_FALSE | MAY_BE_TRUE),
#endif
#if HAVE_STRPTIME
- F1("strptime", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING),
+ F1("strptime", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING),
#endif
F0("flush", MAY_BE_NULL),
- F1("wordwrap", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("htmlspecialchars", MAY_BE_NULL | MAY_BE_STRING),
- F1("htmlentities", MAY_BE_NULL | MAY_BE_STRING),
- FN("html_entity_decode", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- FN("htmlspecialchars_decode", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("get_html_translation_table", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_STRING),
- F1("sha1", MAY_BE_NULL | MAY_BE_STRING),
- F1("sha1_file", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("md5", MAY_BE_NULL | MAY_BE_STRING),
- F1("md5_file", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F0("crc32", MAY_BE_NULL | MAY_BE_LONG),
- F1("iptcparse", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ARRAY),
- F1("iptcembed", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("getimagesize", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING),
- F1("getimagesizefromstring", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING),
- F1("image_type_to_mime_type", MAY_BE_NULL | MAY_BE_STRING),
+ F1("wordwrap", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("htmlspecialchars", MAY_BE_STRING),
+ F1("htmlentities", MAY_BE_STRING),
+ FN("html_entity_decode", MAY_BE_FALSE | MAY_BE_STRING),
+ FN("htmlspecialchars_decode", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("get_html_translation_table", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_STRING),
+ F1("sha1", MAY_BE_STRING),
+ F1("sha1_file", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("md5", MAY_BE_STRING),
+ F1("md5_file", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("iptcparse", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ARRAY),
+ F1("iptcembed", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("getimagesize", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING),
+ F1("getimagesizefromstring", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING),
+ F1("image_type_to_mime_type", MAY_BE_STRING),
F1("image_type_to_extension", MAY_BE_FALSE | MAY_BE_STRING),
- F0("phpinfo", MAY_BE_NULL | MAY_BE_TRUE),
- F1("phpversion", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F0("phpcredits", MAY_BE_NULL | MAY_BE_TRUE),
- I1("php_sapi_name", MAY_BE_FALSE | MAY_BE_STRING),
- F1("php_uname", MAY_BE_NULL | MAY_BE_STRING),
- I1("php_ini_scanned_files", MAY_BE_FALSE | MAY_BE_STRING),
- I1("php_ini_loaded_file", MAY_BE_FALSE | MAY_BE_STRING),
- F0("strnatcmp", MAY_BE_NULL | MAY_BE_LONG),
- F0("strnatcasecmp", MAY_BE_NULL | MAY_BE_LONG),
- F0("substr_count", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("strspn", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("strcspn", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F1("strtok", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- FN("strtoupper", MAY_BE_NULL | MAY_BE_STRING),
- FN("strtolower", MAY_BE_NULL | MAY_BE_STRING),
- F0("strpos", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("stripos", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("strrpos", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("strripos", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F1("strrev", MAY_BE_NULL | MAY_BE_STRING),
- F1("hebrev", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("hebrevc", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("nl2br", MAY_BE_NULL | MAY_BE_STRING),
- F1("basename", MAY_BE_NULL | MAY_BE_STRING),
+ F0("phpinfo", MAY_BE_TRUE),
+ F1("phpversion", MAY_BE_FALSE | MAY_BE_STRING),
+ F0("phpcredits", MAY_BE_TRUE),
+ F1("php_sapi_name", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("php_uname", MAY_BE_STRING),
+ F1("php_ini_scanned_files", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("php_ini_loaded_file", MAY_BE_FALSE | MAY_BE_STRING),
+ F0("substr_count", MAY_BE_FALSE | MAY_BE_LONG),
+ F0("strspn", MAY_BE_FALSE | MAY_BE_LONG),
+ F0("strcspn", MAY_BE_FALSE | MAY_BE_LONG),
+ F1("strtok", MAY_BE_FALSE | MAY_BE_STRING),
+ FN("strtoupper", MAY_BE_STRING),
+ FN("strtolower", MAY_BE_STRING),
+ F0("strpos", MAY_BE_FALSE | MAY_BE_LONG),
+ F0("stripos", MAY_BE_FALSE | MAY_BE_LONG),
+ F0("strrpos", MAY_BE_FALSE | MAY_BE_LONG),
+ F0("strripos", MAY_BE_FALSE | MAY_BE_LONG),
+ F1("strrev", MAY_BE_STRING),
+ F1("hebrev", MAY_BE_STRING),
+ F1("hebrevc", MAY_BE_STRING),
+ FN("nl2br", MAY_BE_STRING),
+ F1("basename", MAY_BE_STRING),
F1("dirname", MAY_BE_NULL | MAY_BE_STRING),
- F1("pathinfo", MAY_BE_NULL | MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_STRING),
- F1("stripslashes", MAY_BE_NULL | MAY_BE_STRING),
- F1("stripcslashes", MAY_BE_NULL | MAY_BE_STRING),
- F1("strstr", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("stristr", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("strrchr", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("str_shuffle", MAY_BE_NULL | MAY_BE_STRING),
- F1("str_word_count", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
- F1("str_split", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
+ F1("pathinfo", MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_STRING),
+ F1("stripslashes", MAY_BE_STRING),
+ F1("stripcslashes", MAY_BE_STRING),
+ F1("strstr", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("stristr", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("strrchr", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("str_shuffle", MAY_BE_STRING),
+ F1("str_word_count", MAY_BE_FALSE | MAY_BE_LONG | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
+ F1("str_split", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
F1("strpbrk", MAY_BE_FALSE | MAY_BE_STRING),
F0("substr_compare", MAY_BE_FALSE | MAY_BE_LONG),
- F0("strcoll", MAY_BE_NULL | MAY_BE_LONG),
#ifdef HAVE_STRFMON
- F1("money_format", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
+ F1("money_format", MAY_BE_FALSE | MAY_BE_STRING),
#endif
- FN("substr", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- FN("substr_replace", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_STRING),
- F1("quotemeta", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- FN("ucfirst", MAY_BE_NULL | MAY_BE_STRING),
- FN("lcfirst", MAY_BE_NULL | MAY_BE_STRING),
- F1("ucwords", MAY_BE_NULL | MAY_BE_STRING),
- FN("strtr", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- FN("addslashes", MAY_BE_NULL | MAY_BE_STRING),
- F1("addcslashes", MAY_BE_NULL | MAY_BE_STRING),
- FN("rtrim", MAY_BE_NULL | MAY_BE_STRING),
- FN("str_replace", MAY_BE_NULL | MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_ARRAY | MAY_BE_ARRAY_OF_OBJECT),
- FN("str_ireplace", MAY_BE_NULL | MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_ARRAY | MAY_BE_ARRAY_OF_OBJECT),
+ FN("substr", MAY_BE_FALSE | MAY_BE_STRING),
+ FN("substr_replace", MAY_BE_FALSE | MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_STRING),
+ F1("quotemeta", MAY_BE_STRING),
+ FN("ucfirst", MAY_BE_STRING),
+ FN("lcfirst", MAY_BE_STRING),
+ F1("ucwords", MAY_BE_STRING),
+ FN("strtr", MAY_BE_FALSE | MAY_BE_STRING),
+ FN("addslashes", MAY_BE_STRING),
+ F1("addcslashes", MAY_BE_STRING),
+ FN("rtrim", MAY_BE_STRING),
+ FN("chop", MAY_BE_STRING),
+ FN("str_replace", MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_ARRAY | MAY_BE_ARRAY_OF_OBJECT),
+ FN("str_ireplace", MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_ARRAY | MAY_BE_ARRAY_OF_OBJECT),
F1("str_repeat", MAY_BE_NULL | MAY_BE_STRING),
- F1("count_chars", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_LONG),
- F1("chunk_split", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- FN("trim", MAY_BE_NULL | MAY_BE_STRING),
- FN("ltrim", MAY_BE_NULL | MAY_BE_STRING),
- F1("strip_tags", MAY_BE_NULL | MAY_BE_STRING),
- F0("similar_text", MAY_BE_NULL | MAY_BE_LONG),
- F1("explode", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
- FN("implode", MAY_BE_NULL | MAY_BE_STRING),
- FN("join", MAY_BE_NULL | MAY_BE_STRING),
- FN("setlocale", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
+ F1("count_chars", MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_LONG),
+ F1("chunk_split", MAY_BE_FALSE | MAY_BE_STRING),
+ FN("trim", MAY_BE_STRING),
+ FN("ltrim", MAY_BE_STRING),
+ F1("strip_tags", MAY_BE_STRING),
+ F1("explode", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
+ FN("implode", MAY_BE_STRING),
+ FN("join", MAY_BE_STRING),
+ FN("setlocale", MAY_BE_FALSE | MAY_BE_STRING),
F1("localeconv", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_ARRAY),
#if HAVE_NL_LANGINFO
- F1("nl_langinfo", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
+ F1("nl_langinfo", MAY_BE_FALSE | MAY_BE_STRING),
#endif
- F1("soundex", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F0("levenshtein", MAY_BE_NULL | MAY_BE_LONG),
- F1("chr", MAY_BE_NULL | MAY_BE_STRING),
- F0("ord", MAY_BE_NULL | MAY_BE_LONG),
- F0("parse_str", MAY_BE_NULL),
+ F1("soundex", MAY_BE_FALSE | MAY_BE_STRING),
+ F0("levenshtein", MAY_BE_LONG),
+ F1("chr", MAY_BE_STRING),
F1("str_getcsv", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_NULL | MAY_BE_ARRAY_OF_STRING),
F1("str_pad", MAY_BE_NULL | MAY_BE_STRING),
- F1("chop", MAY_BE_NULL | MAY_BE_STRING),
- F1("strchr", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
+ F1("strchr", MAY_BE_FALSE | MAY_BE_STRING),
F1("sprintf", MAY_BE_FALSE | MAY_BE_STRING),
F0("printf", MAY_BE_FALSE | MAY_BE_LONG),
F0("vprintf", MAY_BE_FALSE | MAY_BE_LONG),
F1("vsprintf", MAY_BE_FALSE | MAY_BE_STRING),
- F0("fprintf", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("vfprintf", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
+ F0("fprintf", MAY_BE_FALSE | MAY_BE_LONG),
+ F0("vfprintf", MAY_BE_FALSE | MAY_BE_LONG),
F1("sscanf", MAY_BE_NULL | MAY_BE_LONG | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_ANY),
F1("fscanf", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_ANY),
- F1("parse_url", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG | MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_LONG),
- F1("urlencode", MAY_BE_NULL | MAY_BE_STRING),
- F1("urldecode", MAY_BE_NULL | MAY_BE_STRING),
- F1("rawurlencode", MAY_BE_NULL | MAY_BE_STRING),
- F1("rawurldecode", MAY_BE_NULL | MAY_BE_STRING),
+ F1("parse_url", MAY_BE_FALSE | MAY_BE_LONG | MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_LONG),
+ F1("urlencode", MAY_BE_STRING),
+ F1("urldecode", MAY_BE_STRING),
+ F1("rawurlencode", MAY_BE_STRING),
+ F1("rawurldecode", MAY_BE_STRING),
F1("http_build_query", MAY_BE_FALSE | MAY_BE_STRING),
#if defined(HAVE_SYMLINK) || defined(PHP_WIN32)
- F1("readlink", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F0("linkinfo", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("symlink", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("link", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
+ F1("readlink", MAY_BE_FALSE | MAY_BE_STRING),
+ F0("linkinfo", MAY_BE_FALSE | MAY_BE_LONG),
+ F0("symlink", MAY_BE_FALSE | MAY_BE_TRUE),
+ F0("link", MAY_BE_FALSE | MAY_BE_TRUE),
#endif
F0("unlink", MAY_BE_FALSE | MAY_BE_TRUE),
F1("exec", MAY_BE_FALSE | MAY_BE_STRING),
F1("system", MAY_BE_FALSE | MAY_BE_STRING),
- F1("escapeshellcmd", MAY_BE_NULL | MAY_BE_STRING),
- F1("escapeshellarg", MAY_BE_NULL | MAY_BE_STRING),
+ F1("escapeshellcmd", MAY_BE_STRING),
+ F1("escapeshellarg", MAY_BE_STRING),
F1("passthru", MAY_BE_NULL | MAY_BE_FALSE),
F1("shell_exec", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
#ifdef PHP_CAN_SUPPORT_PROC_OPEN
@@ -418,111 +258,89 @@ static const func_info_t func_infos[] = {
F0("getrandmax", MAY_BE_NULL | MAY_BE_LONG),
F0("mt_rand", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
F0("mt_srand", MAY_BE_NULL),
- I0("mt_getrandmax", MAY_BE_LONG),
+ F0("mt_getrandmax", MAY_BE_LONG),
#if HAVE_GETSERVBYNAME
- F0("getservbyname", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
+ F0("getservbyname", MAY_BE_FALSE | MAY_BE_LONG),
#endif
#if HAVE_GETSERVBYPORT
- F1("getservbyport", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
+ F1("getservbyport", MAY_BE_FALSE | MAY_BE_STRING),
#endif
#if HAVE_GETPROTOBYNAME
- F0("getprotobyname", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
+ F0("getprotobyname", MAY_BE_FALSE | MAY_BE_LONG),
#endif
#if HAVE_GETPROTOBYNUMBER
- F1("getprotobynumber", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
+ F1("getprotobynumber", MAY_BE_FALSE | MAY_BE_STRING),
#endif
F0("getmyuid", MAY_BE_FALSE | MAY_BE_LONG),
F0("getmygid", MAY_BE_FALSE | MAY_BE_LONG),
F0("getmypid", MAY_BE_FALSE | MAY_BE_LONG),
F0("getmyinode", MAY_BE_FALSE | MAY_BE_LONG),
- F0("getlastmod", MAY_BE_FALSE | MAY_BE_LONG),
- F1("base64_decode", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("base64_encode", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("password_hash", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("password_get_info", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_ARRAY),
- F0("password_needs_rehash", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
+ F1("base64_decode", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("base64_encode", MAY_BE_STRING),
+ F1("password_hash", MAY_BE_NULL | MAY_BE_STRING),
+ F1("password_get_info", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_ARRAY),
+ F0("password_needs_rehash", MAY_BE_FALSE | MAY_BE_TRUE),
F0("password_verify", MAY_BE_FALSE | MAY_BE_TRUE),
F1("convert_uuencode", MAY_BE_FALSE | MAY_BE_STRING),
F1("convert_uudecode", MAY_BE_FALSE | MAY_BE_STRING),
- F0("abs", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG | MAY_BE_DOUBLE),
- F0("ceil", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_DOUBLE),
- F0("floor", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_DOUBLE),
- F0("round", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_DOUBLE),
- F0("sin", MAY_BE_NULL | MAY_BE_DOUBLE),
- F0("cos", MAY_BE_NULL | MAY_BE_DOUBLE),
- F0("tan", MAY_BE_NULL | MAY_BE_DOUBLE),
- F0("asin", MAY_BE_NULL | MAY_BE_DOUBLE),
- F0("acos", MAY_BE_NULL | MAY_BE_DOUBLE),
- F0("atan", MAY_BE_NULL | MAY_BE_DOUBLE),
- F0("atanh", MAY_BE_NULL | MAY_BE_DOUBLE),
- F0("atan2", MAY_BE_NULL | MAY_BE_DOUBLE),
- F0("sinh", MAY_BE_NULL | MAY_BE_DOUBLE),
- F0("cosh", MAY_BE_NULL | MAY_BE_DOUBLE),
- F0("tanh", MAY_BE_NULL | MAY_BE_DOUBLE),
- F0("asinh", MAY_BE_NULL | MAY_BE_DOUBLE),
- F0("acosh", MAY_BE_NULL | MAY_BE_DOUBLE),
- F0("expm1", MAY_BE_NULL | MAY_BE_DOUBLE),
- F0("log1p", MAY_BE_NULL | MAY_BE_DOUBLE),
- F0("pi", MAY_BE_DOUBLE),
- F0("is_finite", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("is_nan", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("is_infinite", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("pow", MAY_BE_NULL | MAY_BE_LONG | MAY_BE_DOUBLE),
- F0("exp", MAY_BE_NULL | MAY_BE_DOUBLE),
- F0("log", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_DOUBLE),
- F0("log10", MAY_BE_NULL | MAY_BE_DOUBLE),
- F0("sqrt", MAY_BE_NULL | MAY_BE_DOUBLE),
- F0("hypot", MAY_BE_NULL | MAY_BE_DOUBLE),
- F0("deg2rad", MAY_BE_NULL | MAY_BE_DOUBLE),
- F0("rad2deg", MAY_BE_NULL | MAY_BE_DOUBLE),
- F0("bindec", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG | MAY_BE_DOUBLE),
- F0("hexdec", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG | MAY_BE_DOUBLE),
- F0("octdec", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG | MAY_BE_DOUBLE),
- F1("decbin", MAY_BE_NULL | MAY_BE_STRING),
- F1("decoct", MAY_BE_NULL | MAY_BE_STRING),
- FC("dechex", zend_dechex_info),
- F1("base_convert", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("number_format", MAY_BE_NULL | MAY_BE_STRING),
- F0("fmod", MAY_BE_NULL | MAY_BE_DOUBLE),
+ F0("abs", MAY_BE_LONG | MAY_BE_DOUBLE),
+ F0("ceil", MAY_BE_DOUBLE),
+ F0("floor", MAY_BE_DOUBLE),
+ F0("round", MAY_BE_FALSE | MAY_BE_DOUBLE),
+ F0("expm1", MAY_BE_DOUBLE),
+ F0("log1p", MAY_BE_DOUBLE),
+ F1("pow", MAY_BE_NULL | MAY_BE_LONG | MAY_BE_DOUBLE | MAY_BE_OBJECT),
+ F0("exp", MAY_BE_DOUBLE),
+ F0("log", MAY_BE_FALSE | MAY_BE_DOUBLE),
+ F0("log10", MAY_BE_DOUBLE),
+ F0("sqrt", MAY_BE_DOUBLE),
+ F0("hypot", MAY_BE_DOUBLE),
+ F0("deg2rad", MAY_BE_DOUBLE),
+ F0("rad2deg", MAY_BE_DOUBLE),
+ F0("bindec", MAY_BE_LONG | MAY_BE_DOUBLE),
+ F0("hexdec", MAY_BE_LONG | MAY_BE_DOUBLE),
+ F0("octdec", MAY_BE_LONG | MAY_BE_DOUBLE),
+ F1("decbin", MAY_BE_STRING),
+ F1("decoct", MAY_BE_STRING),
+ F1("dechex", MAY_BE_STRING),
+ F1("base_convert", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("number_format", MAY_BE_STRING),
+ F0("fmod", MAY_BE_DOUBLE),
#ifdef HAVE_INET_NTOP
F1("inet_ntop", MAY_BE_FALSE | MAY_BE_STRING),
#endif
#ifdef HAVE_INET_PTON
F1("inet_pton", MAY_BE_FALSE | MAY_BE_STRING),
#endif
- F0("ip2long", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F1("long2ip", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
+ F0("ip2long", MAY_BE_FALSE | MAY_BE_LONG),
+ F1("long2ip", MAY_BE_FALSE | MAY_BE_STRING),
F1("getenv", MAY_BE_FALSE | MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_STRING),
#ifdef HAVE_PUTENV
- F0("putenv", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
+ F0("putenv", MAY_BE_FALSE | MAY_BE_TRUE),
#endif
F1("getopt", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_FALSE | MAY_BE_ARRAY_OF_TRUE | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_ARRAY),
#ifdef HAVE_GETLOADAVG
F1("sys_getloadavg", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_DOUBLE),
#endif
#ifdef HAVE_GETTIMEOFDAY
- F1("microtime", MAY_BE_NULL | MAY_BE_DOUBLE | MAY_BE_STRING),
- F1("gettimeofday", MAY_BE_NULL | MAY_BE_DOUBLE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_LONG),
+ F1("microtime", MAY_BE_DOUBLE | MAY_BE_STRING),
+ F1("gettimeofday", MAY_BE_DOUBLE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_LONG),
#endif
#ifdef HAVE_GETRUSAGE
- F1("getrusage", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_LONG),
+ F1("getrusage", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_LONG),
#endif
#ifdef HAVE_GETTIMEOFDAY
- F1("uniqid", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
+ F1("uniqid", MAY_BE_STRING),
#endif
- F1("quoted_printable_decode", MAY_BE_NULL | MAY_BE_STRING),
- F1("quoted_printable_encode", MAY_BE_NULL | MAY_BE_STRING),
- F1("convert_cyr_string", MAY_BE_NULL | MAY_BE_STRING),
- I1("get_current_user", MAY_BE_STRING),
- F0("set_time_limit", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("header_register_callback", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F1("get_cfg_var", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_ARRAY),
- I0("magic_quotes_runtime", MAY_BE_FALSE),
- I0("set_magic_quotes_runtime", MAY_BE_FALSE),
- I0("get_magic_quotes_gpc", MAY_BE_FALSE),
- I0("get_magic_quotes_runtime", MAY_BE_FALSE),
- F0("error_log", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- I1("error_get_last", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING),
+ F1("quoted_printable_decode", MAY_BE_STRING),
+ F1("quoted_printable_encode", MAY_BE_STRING),
+ F1("convert_cyr_string", MAY_BE_STRING),
+ F1("get_current_user", MAY_BE_STRING),
+ F1("get_cfg_var", MAY_BE_FALSE | MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_ARRAY),
+ F0("get_magic_quotes_gpc", MAY_BE_FALSE),
+ F0("get_magic_quotes_runtime", MAY_BE_FALSE),
+ F0("error_log", MAY_BE_FALSE | MAY_BE_TRUE),
+ F1("error_get_last", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING),
FN("call_user_func", UNKNOWN_INFO),
FN("call_user_func_array", UNKNOWN_INFO),
FN("call_user_method", UNKNOWN_INFO),
@@ -543,73 +361,50 @@ static const func_info_t func_infos[] = {
F1("highlight_file", MAY_BE_FALSE | MAY_BE_TRUE | MAY_BE_STRING),
F1("show_source", MAY_BE_FALSE | MAY_BE_STRING),
F1("highlight_string", MAY_BE_FALSE | MAY_BE_TRUE | MAY_BE_STRING),
- F1("php_strip_whitespace", MAY_BE_FALSE | MAY_BE_STRING),
- FN("ini_get", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("ini_get_all", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_NULL | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_ARRAY),
- FN("ini_set", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
+ F1("php_strip_whitespace", MAY_BE_STRING),
+ FN("ini_get", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("ini_get_all", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_NULL | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_ARRAY),
+ FN("ini_set", MAY_BE_FALSE | MAY_BE_STRING),
F1("ini_alter", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
F0("ini_restore", MAY_BE_NULL),
- I1("get_include_path", MAY_BE_FALSE | MAY_BE_STRING),
- F1("set_include_path", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
+ F1("get_include_path", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("set_include_path", MAY_BE_FALSE | MAY_BE_STRING),
F0("restore_include_path", MAY_BE_NULL),
- F0("setcookie", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("setrawcookie", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("header", MAY_BE_NULL),
- F0("header_remove", MAY_BE_NULL),
- F0("headers_sent", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
F1("headers_list", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
F0("http_response_code", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
F0("connection_aborted", MAY_BE_LONG),
F0("connection_status", MAY_BE_LONG),
- F0("ignore_user_abort", MAY_BE_NULL | MAY_BE_LONG),
+ F0("ignore_user_abort", MAY_BE_LONG),
F1("parse_ini_file", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_NULL | MAY_BE_ARRAY_OF_FALSE | MAY_BE_ARRAY_OF_TRUE | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_DOUBLE | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_ARRAY),
F1("parse_ini_string", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_NULL | MAY_BE_ARRAY_OF_FALSE | MAY_BE_ARRAY_OF_TRUE | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_DOUBLE | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_ARRAY),
#if ZEND_DEBUG
F1("config_get_hash", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_ARRAY),
#endif
- F0("is_uploaded_file", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("move_uploaded_file", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F1("gethostbyaddr", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("gethostbyname", MAY_BE_NULL | MAY_BE_STRING),
- F1("gethostbynamel", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
+ F0("move_uploaded_file", MAY_BE_FALSE | MAY_BE_TRUE),
+ F1("gethostbyaddr", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("gethostbyname", MAY_BE_STRING),
+ F1("gethostbynamel", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
#ifdef HAVE_GETHOSTNAME
F1("gethostname", MAY_BE_FALSE | MAY_BE_STRING),
#endif
#if defined(PHP_WIN32) || HAVE_DNS_SEARCH_FUNC
- F0("dns_check_record", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("checkdnsrr", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
+ F0("dns_check_record", MAY_BE_FALSE | MAY_BE_TRUE),
+ F0("checkdnsrr", MAY_BE_FALSE | MAY_BE_TRUE),
# if defined(PHP_WIN32) || HAVE_FULL_DNS_FUNCS
- F0("dns_get_mx", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("getmxrr", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F1("dns_get_record", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_ARRAY),
+ F0("dns_get_mx", MAY_BE_FALSE | MAY_BE_TRUE),
+ F0("getmxrr", MAY_BE_FALSE | MAY_BE_TRUE),
+ F1("dns_get_record", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_ARRAY),
# endif
#endif
- F0("intval", MAY_BE_NULL | MAY_BE_LONG),
- F0("floatval", MAY_BE_NULL | MAY_BE_DOUBLE),
- F0("doubleval", MAY_BE_NULL | MAY_BE_DOUBLE),
- FN("strval", MAY_BE_NULL | MAY_BE_STRING),
- F0("boolval", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- FN("gettype", MAY_BE_NULL | MAY_BE_STRING),
- F0("settype", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- FC("is_null", zend_is_type_info),
- F0("is_resource", MAY_BE_FALSE | MAY_BE_TRUE), // TODO: inline with support for closed resources
- FC("is_bool", zend_is_type_info),
- FC("is_long", zend_is_type_info),
- FC("is_float", zend_is_type_info),
- FC("is_int", zend_is_type_info),
- FC("is_integer", zend_is_type_info),
- FC("is_double", zend_is_type_info),
- FC("is_real", zend_is_type_info),
- F0("is_numeric", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- FC("is_string", zend_is_type_info),
- FC("is_array", zend_is_type_info),
- F0("is_object", MAY_BE_FALSE | MAY_BE_TRUE), // TODO: inline with support for incomplete class
- F0("is_scalar", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("is_callable", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("is_countable", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("is_iterable", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
+ F0("intval", MAY_BE_LONG),
+ F0("floatval", MAY_BE_DOUBLE),
+ F0("doubleval", MAY_BE_DOUBLE),
+ FN("strval", MAY_BE_STRING),
+ F0("boolval", MAY_BE_FALSE | MAY_BE_TRUE),
+ FN("gettype", MAY_BE_STRING),
+ F0("settype", MAY_BE_FALSE | MAY_BE_TRUE),
F0("pclose", MAY_BE_FALSE | MAY_BE_LONG),
- F1("popen", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_RESOURCE),
+ F1("popen", MAY_BE_FALSE | MAY_BE_RESOURCE),
F0("readfile", MAY_BE_FALSE | MAY_BE_LONG),
F0("rewind", MAY_BE_FALSE | MAY_BE_TRUE),
F0("rmdir", MAY_BE_FALSE | MAY_BE_TRUE),
@@ -618,7 +413,6 @@ static const func_info_t func_infos[] = {
F0("feof", MAY_BE_FALSE | MAY_BE_TRUE),
F1("fgetc", MAY_BE_FALSE | MAY_BE_STRING),
F1("fgets", MAY_BE_FALSE | MAY_BE_STRING),
- F1("fgetss", MAY_BE_FALSE | MAY_BE_STRING),
F1("fread", MAY_BE_FALSE | MAY_BE_STRING),
F1("fopen", MAY_BE_FALSE | MAY_BE_RESOURCE),
F0("fpassthru", MAY_BE_FALSE | MAY_BE_LONG),
@@ -631,13 +425,13 @@ static const func_info_t func_infos[] = {
F0("fputs", MAY_BE_FALSE | MAY_BE_LONG),
F0("mkdir", MAY_BE_FALSE | MAY_BE_TRUE),
F0("rename", MAY_BE_FALSE | MAY_BE_TRUE),
- F0("copy", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F1("tempnam", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
+ F0("copy", MAY_BE_FALSE | MAY_BE_TRUE),
+ F1("tempnam", MAY_BE_FALSE | MAY_BE_STRING),
F1("tmpfile", MAY_BE_FALSE | MAY_BE_RESOURCE),
- F1("file", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
- F1("file_get_contents", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F0("file_put_contents", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("stream_select", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
+ F1("file", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
+ F1("file_get_contents", MAY_BE_FALSE | MAY_BE_STRING),
+ F0("file_put_contents", MAY_BE_FALSE | MAY_BE_LONG),
+ F0("stream_select", MAY_BE_FALSE | MAY_BE_LONG),
F1("stream_context_create", MAY_BE_FALSE | MAY_BE_RESOURCE),
F0("stream_context_set_params", MAY_BE_FALSE | MAY_BE_TRUE),
F1("stream_context_get_params", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ANY),
@@ -665,44 +459,40 @@ static const func_info_t func_infos[] = {
F1("stream_get_contents", MAY_BE_FALSE | MAY_BE_STRING),
F0("stream_supports_lock", MAY_BE_FALSE | MAY_BE_TRUE),
F1("fgetcsv", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_NULL | MAY_BE_ARRAY_OF_STRING),
- F0("fputcsv", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("flock", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F1("get_meta_tags", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_STRING),
+ F0("fputcsv", MAY_BE_FALSE | MAY_BE_LONG),
+ F0("flock", MAY_BE_FALSE | MAY_BE_TRUE),
+ F1("get_meta_tags", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_STRING),
F0("stream_set_read_buffer", MAY_BE_FALSE | MAY_BE_LONG),
F0("stream_set_write_buffer", MAY_BE_FALSE | MAY_BE_LONG),
F0("set_file_buffer", MAY_BE_FALSE | MAY_BE_LONG),
F0("stream_set_chunk_size", MAY_BE_FALSE | MAY_BE_LONG),
- F0("stream_set_blocking", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("socket_set_blocking", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F1("stream_get_meta_data", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ANY),
+ F0("stream_set_blocking", MAY_BE_FALSE | MAY_BE_TRUE),
+ F0("socket_set_blocking", MAY_BE_FALSE | MAY_BE_TRUE),
+ F1("stream_get_meta_data", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ANY),
F1("stream_get_line", MAY_BE_FALSE | MAY_BE_STRING),
- F0("stream_wrapper_register", MAY_BE_FALSE | MAY_BE_TRUE),
- F0("stream_register_wrapper", MAY_BE_FALSE | MAY_BE_TRUE),
- F0("stream_wrapper_unregister", MAY_BE_FALSE | MAY_BE_TRUE),
- F0("stream_wrapper_restore", MAY_BE_FALSE | MAY_BE_TRUE),
F1("stream_get_wrappers", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
F1("stream_get_transports", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
- F1("stream_resolve_include_path", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
+ F1("stream_resolve_include_path", MAY_BE_FALSE | MAY_BE_STRING),
F0("stream_is_local", MAY_BE_FALSE | MAY_BE_TRUE),
- F1("get_headers", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_ARRAY),
+ F1("get_headers", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_ARRAY),
#if HAVE_SYS_TIME_H || defined(PHP_WIN32)
- F0("stream_set_timeout", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("socket_set_timeout", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
+ F0("stream_set_timeout", MAY_BE_FALSE | MAY_BE_TRUE),
+ F0("socket_set_timeout", MAY_BE_FALSE | MAY_BE_TRUE),
#endif
- F1("socket_get_status", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ANY),
+ F1("socket_get_status", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ANY),
#if HAVE_REALPATH || defined(ZTS)
- F1("realpath", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
+ F1("realpath", MAY_BE_FALSE | MAY_BE_STRING),
#endif
#ifdef HAVE_FNMATCH
- F0("fnmatch", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
+ F0("fnmatch", MAY_BE_FALSE | MAY_BE_TRUE),
#endif
F1("fsockopen", MAY_BE_FALSE | MAY_BE_RESOURCE),
FN("pfsockopen", MAY_BE_FALSE | MAY_BE_RESOURCE),
F1("pack", MAY_BE_FALSE | MAY_BE_STRING),
- F1("unpack", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY),
+ F1("unpack", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY),
F1("get_browser", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_OBJECT | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ANY),
- F1("crypt", MAY_BE_NULL | MAY_BE_STRING),
- FN("opendir", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_RESOURCE),
+ F1("crypt", MAY_BE_STRING),
+ FN("opendir", MAY_BE_FALSE | MAY_BE_RESOURCE),
F0("closedir", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
F0("chdir", MAY_BE_FALSE | MAY_BE_TRUE),
#if defined(HAVE_CHROOT) && !defined(ZTS) && ENABLE_CHROOT_FUNC
@@ -710,86 +500,54 @@ static const func_info_t func_infos[] = {
#endif
F1("getcwd", MAY_BE_FALSE | MAY_BE_STRING),
F0("rewinddir", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F1("readdir", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("dir", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_OBJECT),
- F1("scandir", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
+ F1("readdir", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("dir", MAY_BE_FALSE | MAY_BE_OBJECT),
+ F1("scandir", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
#ifdef HAVE_GLOB
- F1("glob", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
+ F1("glob", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
#endif
- F0("fileatime", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("filectime", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("filegroup", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("fileinode", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("filemtime", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("fileowner", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("fileperms", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("filesize", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F1("filetype", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F0("file_exists", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("is_writable", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("is_writeable", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("is_readable", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("is_executable", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("is_file", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("is_dir", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("is_link", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F1("stat", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_FALSE | MAY_BE_ARRAY_OF_TRUE | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING),
- F1("lstat", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_FALSE | MAY_BE_ARRAY_OF_TRUE | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING),
- F0("chown", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("chgrp", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
+ F0("fileatime", MAY_BE_FALSE | MAY_BE_LONG),
+ F0("filectime", MAY_BE_FALSE | MAY_BE_LONG),
+ F0("filegroup", MAY_BE_FALSE | MAY_BE_LONG),
+ F0("fileinode", MAY_BE_FALSE | MAY_BE_LONG),
+ F0("filemtime", MAY_BE_FALSE | MAY_BE_LONG),
+ F0("fileowner", MAY_BE_FALSE | MAY_BE_LONG),
+ F0("fileperms", MAY_BE_FALSE | MAY_BE_LONG),
+ F0("filesize", MAY_BE_FALSE | MAY_BE_LONG),
+ F1("filetype", MAY_BE_FALSE | MAY_BE_STRING),
+ F0("file_exists", MAY_BE_FALSE | MAY_BE_TRUE),
+ F1("stat", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_FALSE | MAY_BE_ARRAY_OF_TRUE | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING),
+ F1("lstat", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_FALSE | MAY_BE_ARRAY_OF_TRUE | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING),
+ F0("chown", MAY_BE_FALSE | MAY_BE_TRUE),
+ F0("chgrp", MAY_BE_FALSE | MAY_BE_TRUE),
#if HAVE_LCHOWN
- F0("lchown", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
+ F0("lchown", MAY_BE_FALSE | MAY_BE_TRUE),
#endif
#if HAVE_LCHOWN
- F0("lchgrp", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
+ F0("lchgrp", MAY_BE_FALSE | MAY_BE_TRUE),
#endif
- F0("chmod", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
+ F0("chmod", MAY_BE_FALSE | MAY_BE_TRUE),
#if HAVE_UTIME
- F0("touch", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
+ F0("touch", MAY_BE_FALSE | MAY_BE_TRUE),
#endif
F0("clearstatcache", MAY_BE_NULL),
- F0("disk_total_space", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_DOUBLE),
- F0("disk_free_space", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_DOUBLE),
- F0("diskfreespace", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_DOUBLE),
- I0("realpath_cache_size", MAY_BE_LONG),
- I1("realpath_cache_get", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ARRAY),
- F0("mail", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("ezmlm_hash", MAY_BE_NULL | MAY_BE_LONG),
+ F0("disk_total_space", MAY_BE_FALSE | MAY_BE_DOUBLE),
+ F0("disk_free_space", MAY_BE_FALSE | MAY_BE_DOUBLE),
+ F0("diskfreespace", MAY_BE_FALSE | MAY_BE_DOUBLE),
+ F0("realpath_cache_size", MAY_BE_LONG),
+ F1("realpath_cache_get", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ARRAY),
+ F0("mail", MAY_BE_FALSE | MAY_BE_TRUE),
+ F0("ezmlm_hash", MAY_BE_LONG),
#ifdef HAVE_SYSLOG_H
- F0("openlog", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("syslog", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
F0("closelog", MAY_BE_TRUE),
#endif
- F0("lcg_value", MAY_BE_DOUBLE),
- F1("metaphone", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F0("ob_start", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("ob_flush", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("ob_clean", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("ob_end_flush", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("ob_end_clean", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F1("ob_get_flush", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("ob_get_clean", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F0("ob_get_length", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("ob_get_level", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F1("ob_get_status", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_ARRAY),
- FN("ob_get_contents", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F0("ob_implicit_flush", MAY_BE_NULL),
- F1("ob_list_handlers", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
- F0("ksort", MAY_BE_FALSE | MAY_BE_TRUE),
- F0("krsort", MAY_BE_FALSE | MAY_BE_TRUE),
- F0("natsort", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("natcasesort", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("asort", MAY_BE_FALSE | MAY_BE_TRUE),
- F0("arsort", MAY_BE_FALSE | MAY_BE_TRUE),
- F0("sort", MAY_BE_FALSE | MAY_BE_TRUE),
- F0("rsort", MAY_BE_FALSE | MAY_BE_TRUE),
- F0("usort", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("uasort", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("uksort", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("shuffle", MAY_BE_FALSE | MAY_BE_TRUE),
- F0("array_walk", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("array_walk_recursive", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("count", MAY_BE_NULL | MAY_BE_LONG),
+ F1("metaphone", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("ob_get_flush", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("ob_get_clean", MAY_BE_FALSE | MAY_BE_STRING),
+ F0("ob_get_length", MAY_BE_FALSE | MAY_BE_LONG),
+ F1("ob_get_status", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_ARRAY),
+ FN("ob_get_contents", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("ob_list_handlers", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
FN("end", UNKNOWN_INFO),
FN("prev", UNKNOWN_INFO),
FN("next", UNKNOWN_INFO),
@@ -798,129 +556,111 @@ static const func_info_t func_infos[] = {
FN("key", MAY_BE_NULL | MAY_BE_LONG | MAY_BE_STRING),
FN("min", UNKNOWN_INFO),
FN("max", UNKNOWN_INFO),
- F0("in_array", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
FN("array_search", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG | MAY_BE_STRING),
- F0("extract", MAY_BE_NULL | MAY_BE_LONG),
- F1("compact", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
- F1("array_fill", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_ANY),
- F1("array_fill_keys", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ F1("compact", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ F1("array_fill", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_ANY),
+ F1("array_fill_keys", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
FC("range", zend_range_info),
- F0("array_multisort", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("array_push", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
FN("array_pop", UNKNOWN_INFO),
FN("array_shift", UNKNOWN_INFO),
- F0("array_unshift", MAY_BE_NULL | MAY_BE_LONG),
- F1("array_splice", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
- F1("array_slice", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
- FN("array_merge", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
- F1("array_merge_recursive", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
- F1("array_replace", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
- F1("array_replace_recursive", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
- FN("array_keys", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING),
- FN("array_values", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
- F1("array_count_values", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_LONG),
- F1("array_column", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
- F1("array_reverse", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ F1("array_splice", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ F1("array_slice", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ FN("array_merge", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ F1("array_merge_recursive", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ F1("array_replace", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ F1("array_replace_recursive", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ FN("array_keys", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING),
+ FN("array_values", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ F1("array_count_values", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_LONG),
+ F1("array_column", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ F1("array_reverse", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
F1("array_reduce", UNKNOWN_INFO),
- FN("array_pad", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
- F1("array_flip", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING),
- F1("array_change_key_case", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ FN("array_pad", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ F1("array_flip", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING),
+ F1("array_change_key_case", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
F1("array_rand", UNKNOWN_INFO),
- FN("array_unique", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
- F1("array_intersect", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
- F1("array_intersect_key", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
- F1("array_intersect_ukey", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
- F1("array_uintersect", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
- F1("array_intersect_assoc", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
- F1("array_uintersect_assoc", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
- F1("array_intersect_uassoc", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
- F1("array_uintersect_uassoc", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
- FN("array_diff", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
- F1("array_diff_key", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
- F1("array_diff_ukey", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
- F1("array_udiff", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
- F1("array_diff_assoc", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
- F1("array_udiff_assoc", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
- F1("array_diff_uassoc", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
- F1("array_udiff_uassoc", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
- F0("array_sum", MAY_BE_NULL | MAY_BE_LONG | MAY_BE_DOUBLE),
- F0("array_product", MAY_BE_NULL | MAY_BE_LONG | MAY_BE_DOUBLE),
- F1("array_filter", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
- FN("array_map", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
- F1("array_chunk", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
- F1("array_combine", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
- F0("array_key_exists", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
+ FN("array_unique", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ F1("array_intersect", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ F1("array_intersect_key", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ F1("array_intersect_ukey", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ F1("array_uintersect", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ F1("array_intersect_assoc", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ F1("array_uintersect_assoc", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ F1("array_intersect_uassoc", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ F1("array_uintersect_uassoc", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ FN("array_diff", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ F1("array_diff_key", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ F1("array_diff_ukey", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ F1("array_udiff", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ F1("array_diff_assoc", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ F1("array_udiff_assoc", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ F1("array_diff_uassoc", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ F1("array_udiff_uassoc", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ F0("array_sum", MAY_BE_LONG | MAY_BE_DOUBLE),
+ F0("array_product", MAY_BE_LONG | MAY_BE_DOUBLE),
+ F1("array_filter", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ FN("array_map", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ F1("array_chunk", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ F1("array_combine", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
FN("array_key_first", MAY_BE_NULL | MAY_BE_LONG | MAY_BE_STRING),
FN("array_key_last", MAY_BE_NULL | MAY_BE_LONG | MAY_BE_STRING),
F1("pos", UNKNOWN_INFO),
- F0("sizeof", MAY_BE_NULL | MAY_BE_LONG),
- F0("key_exists", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("assert", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
F1("assert_options", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG | MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_OBJECT | MAY_BE_OBJECT),
F0("version_compare", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE | MAY_BE_LONG),
-#if HAVE_FTOK
- F0("ftok", MAY_BE_NULL | MAY_BE_LONG),
-#endif
- F1("str_rot13", MAY_BE_NULL | MAY_BE_STRING),
- I1("stream_get_filters", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
+ F1("str_rot13", MAY_BE_STRING),
+ F1("stream_get_filters", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
F0("stream_filter_register", MAY_BE_FALSE | MAY_BE_TRUE),
- F1("stream_bucket_make_writeable", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_OBJECT),
+ F1("stream_bucket_make_writeable", MAY_BE_NULL | MAY_BE_OBJECT),
F1("stream_bucket_prepend", MAY_BE_FALSE | MAY_BE_OBJECT),
F1("stream_bucket_append", MAY_BE_FALSE | MAY_BE_OBJECT),
F1("stream_bucket_new", MAY_BE_FALSE | MAY_BE_OBJECT),
- F0("output_add_rewrite_var", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
F0("output_reset_rewrite_vars", MAY_BE_FALSE),
- I1("sys_get_temp_dir", MAY_BE_STRING),
+ F1("sys_get_temp_dir", MAY_BE_STRING),
/* ext/date */
F0("strtotime", MAY_BE_FALSE | MAY_BE_LONG),
- F1("date", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("date", MAY_BE_STRING),
F0("idate", MAY_BE_FALSE | MAY_BE_LONG),
- F1("gmdate", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("gmdate", MAY_BE_STRING),
F0("mktime", MAY_BE_FALSE | MAY_BE_LONG),
F0("gmmktime", MAY_BE_FALSE | MAY_BE_LONG),
- F0("checkdate", MAY_BE_FALSE | MAY_BE_TRUE),
F1("strftime", MAY_BE_FALSE | MAY_BE_STRING),
F1("gmstrftime", MAY_BE_FALSE | MAY_BE_STRING),
- F0("time", MAY_BE_LONG),
- F1("localtime", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_LONG),
- F1("getdate", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING),
+ F1("localtime", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_LONG),
+ F1("getdate", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING),
F1("date_create", MAY_BE_FALSE | MAY_BE_OBJECT),
F1("date_create_immutable", MAY_BE_FALSE | MAY_BE_OBJECT),
F1("date_create_from_format", MAY_BE_FALSE | MAY_BE_OBJECT),
F1("date_create_immutable_from_format", MAY_BE_FALSE | MAY_BE_OBJECT),
- F1("date_parse", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ANY),
- F1("date_parse_from_format", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ANY),
+ F1("date_parse", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ANY),
+ F1("date_parse_from_format", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ANY),
F1("date_get_last_errors", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_ARRAY),
- F1("date_format", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("date_format", MAY_BE_STRING),
FN("date_modify", MAY_BE_FALSE | MAY_BE_OBJECT),
- FN("date_add", MAY_BE_FALSE | MAY_BE_OBJECT),
- FN("date_sub", MAY_BE_FALSE | MAY_BE_OBJECT),
+ FN("date_add", MAY_BE_OBJECT),
+ FN("date_sub", MAY_BE_OBJECT),
F1("date_timezone_get", MAY_BE_FALSE | MAY_BE_OBJECT),
- FN("date_timezone_set", MAY_BE_FALSE | MAY_BE_OBJECT),
- F0("date_offset_get", MAY_BE_FALSE | MAY_BE_LONG),
- F1("date_diff", MAY_BE_FALSE | MAY_BE_OBJECT),
- FN("date_time_set", MAY_BE_FALSE | MAY_BE_OBJECT),
- FN("date_date_set", MAY_BE_FALSE | MAY_BE_OBJECT),
- FN("date_isodate_set", MAY_BE_FALSE | MAY_BE_OBJECT),
- FN("date_timestamp_set", MAY_BE_FALSE | MAY_BE_OBJECT),
+ FN("date_timezone_set", MAY_BE_OBJECT),
+ F1("date_diff", MAY_BE_OBJECT),
+ FN("date_time_set", MAY_BE_OBJECT),
+ FN("date_date_set", MAY_BE_OBJECT),
+ FN("date_isodate_set", MAY_BE_OBJECT),
+ FN("date_timestamp_set", MAY_BE_OBJECT),
F0("date_timestamp_get", MAY_BE_FALSE | MAY_BE_LONG),
F1("timezone_open", MAY_BE_FALSE | MAY_BE_OBJECT),
- F1("timezone_name_get", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("timezone_name_get", MAY_BE_STRING),
F1("timezone_name_from_abbr", MAY_BE_FALSE | MAY_BE_STRING),
- F0("timezone_offset_get", MAY_BE_FALSE | MAY_BE_LONG),
F1("timezone_transitions_get", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY),
F1("timezone_location_get", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_DOUBLE | MAY_BE_ARRAY_OF_STRING),
F1("timezone_identifiers_list", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
F1("timezone_abbreviations_list", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ARRAY),
F1("timezone_version_get", MAY_BE_STRING),
F1("date_interval_create_from_date_string", MAY_BE_FALSE | MAY_BE_OBJECT),
- F1("date_interval_format", MAY_BE_FALSE | MAY_BE_STRING),
- F0("date_default_timezone_set", MAY_BE_FALSE | MAY_BE_TRUE),
+ F1("date_interval_format", MAY_BE_STRING),
F1("date_default_timezone_get", MAY_BE_STRING),
F1("date_sunrise", MAY_BE_FALSE | MAY_BE_LONG | MAY_BE_DOUBLE | MAY_BE_STRING),
F1("date_sunset", MAY_BE_FALSE | MAY_BE_LONG | MAY_BE_DOUBLE | MAY_BE_STRING),
- F1("date_sun_info", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_FALSE | MAY_BE_ARRAY_OF_TRUE | MAY_BE_ARRAY_OF_LONG),
+ F1("date_sun_info", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_FALSE | MAY_BE_ARRAY_OF_TRUE | MAY_BE_ARRAY_OF_LONG),
/* ext/preg */
F0("preg_match", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
@@ -929,15 +669,14 @@ static const func_info_t func_infos[] = {
FN("preg_replace_callback", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_STRING),
F1("preg_filter", MAY_BE_FALSE | MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_STRING),
F1("preg_split", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_ARRAY),
- FN("preg_quote", MAY_BE_NULL | MAY_BE_STRING),
+ FN("preg_quote", MAY_BE_STRING),
F1("preg_grep", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
- F0("preg_last_error", MAY_BE_NULL | MAY_BE_LONG),
/* ext/mysqli */
F1("mysqli_connect", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_OBJECT),
F0("mysqli_close", MAY_BE_NULL | MAY_BE_TRUE),
- I1("mysqli_connect_error", MAY_BE_NULL | MAY_BE_STRING),
- I0("mysqli_connect_errno", MAY_BE_LONG),
+ F1("mysqli_connect_error", MAY_BE_NULL | MAY_BE_STRING),
+ F0("mysqli_connect_errno", MAY_BE_LONG),
F1("mysqli_get_client_stats", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_STRING),
F1("mysqli_error_list", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_ARRAY),
F1("mysqli_get_links_stats", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_LONG),
@@ -981,8 +720,8 @@ static const func_info_t func_infos[] = {
F0("mysqli_field_count", MAY_BE_NULL | MAY_BE_LONG),
F0("mysqli_field_seek", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
F0("mysqli_field_tell", MAY_BE_NULL | MAY_BE_LONG),
- I1("mysqli_get_client_info", MAY_BE_STRING),
- I0("mysqli_get_client_version", MAY_BE_LONG),
+ F1("mysqli_get_client_info", MAY_BE_STRING),
+ F0("mysqli_get_client_version", MAY_BE_LONG),
F1("mysqli_get_host_info", MAY_BE_NULL | MAY_BE_STRING),
F0("mysqli_get_proto_info", MAY_BE_NULL | MAY_BE_LONG),
F1("mysqli_get_server_info", MAY_BE_NULL | MAY_BE_STRING),
@@ -1030,7 +769,7 @@ static const func_info_t func_infos[] = {
F1("mysqli_stmt_sqlstate", MAY_BE_NULL | MAY_BE_STRING),
F1("mysqli_store_result", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_OBJECT),
F0("mysqli_thread_id", MAY_BE_NULL | MAY_BE_LONG),
- I0("mysqli_thread_safe", MAY_BE_FALSE | MAY_BE_TRUE),
+ F0("mysqli_thread_safe", MAY_BE_FALSE | MAY_BE_TRUE),
F1("mysqli_use_result", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_OBJECT),
F0("mysqli_warning_count", MAY_BE_NULL | MAY_BE_LONG),
@@ -1038,31 +777,19 @@ static const func_info_t func_infos[] = {
F1("curl_init", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_RESOURCE),
F1("curl_copy_handle", MAY_BE_NULL | MAY_BE_RESOURCE),
F1("curl_version", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_ARRAY),
- F0("curl_setopt", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("curl_setopt_array", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
FN("curl_exec", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
F1("curl_getinfo", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING | MAY_BE_LONG | MAY_BE_DOUBLE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY),
- F1("curl_error", MAY_BE_NULL | MAY_BE_STRING),
- F0("curl_errno", MAY_BE_NULL | MAY_BE_LONG),
- F0("curl_close", MAY_BE_NULL),
+ F1("curl_error", MAY_BE_STRING),
F1("curl_strerror", MAY_BE_NULL | MAY_BE_STRING),
F1("curl_multi_strerror", MAY_BE_NULL | MAY_BE_STRING),
- F0("curl_reset", MAY_BE_NULL),
F1("curl_escape", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
F1("curl_unescape", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F0("curl_pause", MAY_BE_NULL | MAY_BE_LONG),
F1("curl_multi_init", MAY_BE_RESOURCE),
- F0("curl_multi_add_handle", MAY_BE_NULL | MAY_BE_LONG),
- F0("curl_multi_remove_handle", MAY_BE_NULL | MAY_BE_LONG),
- F0("curl_multi_select", MAY_BE_NULL | MAY_BE_LONG),
- F0("curl_multi_exec", MAY_BE_NULL | MAY_BE_LONG),
FN("curl_multi_getcontent", MAY_BE_NULL | MAY_BE_STRING),
F1("curl_multi_info_read", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_RESOURCE),
F0("curl_multi_close", MAY_BE_NULL | MAY_BE_FALSE),
F0("curl_multi_setopt", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- I1("curl_share_init", MAY_BE_RESOURCE),
- F0("curl_share_close", MAY_BE_NULL),
- F0("curl_share_setopt", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
+ F1("curl_share_init", MAY_BE_RESOURCE),
F1("curl_file_create", MAY_BE_OBJECT),
/* ext/mbstring */
@@ -1094,7 +821,7 @@ static const func_info_t func_infos[] = {
F1("mb_strimwidth", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
F1("mb_convert_encoding", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY),
F1("mb_detect_encoding", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- I1("mb_list_encodings", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
+ F1("mb_list_encodings", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
F1("mb_encoding_aliases", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
F1("mb_convert_kana", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
F1("mb_encode_mimeheader", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
@@ -1123,25 +850,9 @@ static const func_info_t func_infos[] = {
F0("mb_ereg_search_getpos", MAY_BE_LONG),
F0("mb_ereg_search_setpos", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("mbregex_encoding", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("mbereg", MAY_BE_FALSE | MAY_BE_LONG),
- F0("mberegi", MAY_BE_FALSE | MAY_BE_LONG),
- F1("mbereg_replace", MAY_BE_FALSE | MAY_BE_STRING),
- F1("mberegi_replace", MAY_BE_FALSE | MAY_BE_STRING),
- F1("mbsplit", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
- F0("mbereg_match", MAY_BE_FALSE | MAY_BE_TRUE),
- F0("mbereg_search", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F1("mbereg_search_pos", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_LONG),
- F1("mbereg_search_regs", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_FALSE | MAY_BE_ARRAY_OF_TRUE | MAY_BE_ARRAY_OF_STRING),
- F0("mbereg_search_init", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F1("mbereg_search_getregs", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_FALSE | MAY_BE_ARRAY_OF_TRUE | MAY_BE_ARRAY_OF_STRING),
- F0("mbereg_search_getpos", MAY_BE_LONG),
- F0("mbereg_search_setpos", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
-
/* ext/iconv */
F1("iconv", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
F1("iconv_get_encoding", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_STRING),
- F0("iconv_set_encoding", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
F0("iconv_strlen", MAY_BE_FALSE | MAY_BE_LONG),
F1("iconv_substr", MAY_BE_FALSE | MAY_BE_STRING),
F0("iconv_strpos", MAY_BE_FALSE | MAY_BE_LONG),
@@ -1153,47 +864,22 @@ static const func_info_t func_infos[] = {
/* ext/json */
F1("json_encode", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
F1("json_decode", MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY),
- I0("json_last_error", MAY_BE_LONG),
- I1("json_last_error_msg", MAY_BE_STRING),
+ F1("json_last_error_msg", MAY_BE_STRING),
/* ext/xml */
- FN("xml_parser_create", MAY_BE_FALSE | MAY_BE_RESOURCE),
- FN("xml_parser_create_ns", MAY_BE_FALSE | MAY_BE_RESOURCE),
- F0("xml_set_object", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("xml_set_element_handler", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("xml_set_character_data_handler", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("xml_set_processing_instruction_handler",MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("xml_set_default_handler", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("xml_set_unparsed_entity_decl_handler", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("xml_set_notation_decl_handler", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("xml_set_external_entity_ref_handler", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("xml_set_start_namespace_decl_handler", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("xml_set_end_namespace_decl_handler", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("xml_parse", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("xml_parse_into_struct", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("xml_get_error_code", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
+ FN("xml_parser_create", MAY_BE_FALSE | MAY_BE_OBJECT),
+ FN("xml_parser_create_ns", MAY_BE_FALSE | MAY_BE_OBJECT),
F1("xml_error_string", MAY_BE_NULL | MAY_BE_STRING),
- F0("xml_get_current_line_number", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("xml_get_current_column_number", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("xml_get_current_byte_index", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("xml_parser_free", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("xml_parser_set_option", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
F1("xml_parser_get_option", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG | MAY_BE_STRING),
- F1("utf8_encode", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("utf8_decode", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
+ F1("utf8_encode", MAY_BE_STRING),
+ F1("utf8_decode", MAY_BE_STRING),
/* ext/zlib */
F0("readgzfile", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("gzrewind", MAY_BE_FALSE | MAY_BE_TRUE),
- F0("gzclose", MAY_BE_FALSE | MAY_BE_TRUE),
- F0("gzeof", MAY_BE_FALSE | MAY_BE_TRUE),
F1("gzgetc", MAY_BE_FALSE | MAY_BE_STRING),
F1("gzgets", MAY_BE_FALSE | MAY_BE_STRING),
- F1("gzgetss", MAY_BE_FALSE | MAY_BE_STRING),
F1("gzread", MAY_BE_FALSE | MAY_BE_STRING),
F1("gzopen", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_RESOURCE),
- F0("gzpassthru", MAY_BE_FALSE | MAY_BE_LONG),
- F0("gzseek", MAY_BE_FALSE | MAY_BE_LONG),
F0("gztell", MAY_BE_FALSE | MAY_BE_LONG),
F0("gzwrite", MAY_BE_FALSE | MAY_BE_LONG),
F0("gzputs", MAY_BE_FALSE | MAY_BE_LONG),
@@ -1206,21 +892,17 @@ static const func_info_t func_infos[] = {
F1("gzdecode", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
F1("zlib_encode", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
F1("zlib_decode", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- I1("zlib_get_coding_type", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("zlib_get_coding_type", MAY_BE_FALSE | MAY_BE_STRING),
F1("ob_gzhandler", MAY_BE_FALSE | MAY_BE_STRING),
/* ext/hash */
F1("hash", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F0("hash_equals", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
F1("hash_file", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
F1("hash_hmac", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
F1("hash_hmac_algos", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
F1("hash_hmac_file", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
F1("hash_hkdf", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
F1("hash_init", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_OBJECT),
- F0("hash_update", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("hash_update_stream", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("hash_update_file", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
F1("hash_final", MAY_BE_NULL | MAY_BE_STRING),
F1("hash_copy", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_OBJECT),
F1("hash_algos", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
@@ -1228,7 +910,7 @@ static const func_info_t func_infos[] = {
F1("mhash_keygen_s2k", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
F0("mhash_get_block_size", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
F1("mhash_get_hash_name", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- I0("mhash_count", MAY_BE_LONG),
+ F0("mhash_count", MAY_BE_LONG),
F1("mhash", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
/* ext/sodium */
@@ -1310,28 +992,17 @@ static const func_info_t func_infos[] = {
F1("sodium_crypto_aead_xchacha20poly1305_ietf_keygen", MAY_BE_STRING),
/* ext/session */
- F0("session_set_cookie_params", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- I1("session_get_cookie_params", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ANY),
+ F1("session_get_cookie_params", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ANY),
F1("session_name", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
F1("session_module_name", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F0("session_set_save_handler", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
F1("session_save_path", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
FN("session_id", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F0("session_regenerate_id", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
F1("session_create_id", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
F1("session_cache_limiter", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
F0("session_cache_expire", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- I1("session_encode", MAY_BE_FALSE | MAY_BE_STRING),
- F0("session_decode", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("session_start", MAY_BE_FALSE | MAY_BE_TRUE),
- I0("session_destroy", MAY_BE_FALSE | MAY_BE_TRUE),
- I0("session_unset", MAY_BE_FALSE | MAY_BE_TRUE),
+ F1("session_encode", MAY_BE_FALSE | MAY_BE_STRING),
F0("session_gc", MAY_BE_FALSE | MAY_BE_LONG),
- F0("session_write_close", MAY_BE_FALSE | MAY_BE_TRUE),
F0("session_abort", MAY_BE_FALSE | MAY_BE_TRUE),
- F0("session_reset", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("session_status", MAY_BE_NULL | MAY_BE_LONG),
- I0("session_register_shutdown", MAY_BE_NULL),
/* ext/pgsql */
F1("pg_connect", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_RESOURCE),
@@ -1423,16 +1094,14 @@ static const func_info_t func_infos[] = {
F1("pg_select", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE | MAY_BE_STRING),
/* ext/bcmath */
- F1("bcadd", MAY_BE_NULL | MAY_BE_STRING),
- F1("bcsub", MAY_BE_NULL | MAY_BE_STRING),
- F1("bcmul", MAY_BE_NULL | MAY_BE_STRING),
+ F1("bcadd", MAY_BE_STRING),
+ F1("bcsub", MAY_BE_STRING),
+ F1("bcmul", MAY_BE_STRING),
F1("bcdiv", MAY_BE_NULL | MAY_BE_STRING),
F1("bcmod", MAY_BE_NULL | MAY_BE_STRING),
F1("bcpowmod", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("bcpow", MAY_BE_NULL | MAY_BE_STRING),
+ F1("bcpow", MAY_BE_STRING),
F1("bcsqrt", MAY_BE_NULL | MAY_BE_STRING),
- F0("bccomp", MAY_BE_NULL | MAY_BE_LONG),
- F0("bcscale", MAY_BE_NULL | MAY_BE_LONG),
/* ext/exif */
F1("exif_tagname", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
@@ -1446,7 +1115,7 @@ static const func_info_t func_infos[] = {
FN("filter_var", UNKNOWN_INFO),
F1("filter_input_array", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY),
F1("filter_var_array", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY),
- I1("filter_list", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
+ F1("filter_list", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
F0("filter_id", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
/* ext/gettext */
@@ -1466,23 +1135,8 @@ static const func_info_t func_infos[] = {
F1("bind_textdomain_codeset", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
#endif
- /* ext/ctype */
- F0("ctype_alnum", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("ctype_alpha", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("ctype_cntrl", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("ctype_digit", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("ctype_lower", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("ctype_graph", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("ctype_print", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("ctype_punct", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("ctype_space", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("ctype_upper", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("ctype_xdigit", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
-
/* ext/fileinfo */
F1("finfo_open", MAY_BE_FALSE | MAY_BE_RESOURCE),
- F0("finfo_close", MAY_BE_FALSE | MAY_BE_TRUE),
- F0("finfo_set_flags", MAY_BE_FALSE | MAY_BE_TRUE),
F1("finfo_file", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
F1("finfo_buffer", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
F1("mime_content_type", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
@@ -1490,43 +1144,24 @@ static const func_info_t func_infos[] = {
/* ext/gd */
F1("gd_info", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_FALSE | MAY_BE_ARRAY_OF_TRUE),
F0("imageloadfont", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("imagesetstyle", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
F1("imagecreatetruecolor", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_RESOURCE),
- F0("imageistruecolor", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagetruecolortopalette", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagepalettetotruecolor", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagecolormatch", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagesetthickness", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagefilledellipse", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagefilledarc", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagealphablending", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagesavealpha", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagelayereffect", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
F0("imagecolorallocatealpha", MAY_BE_FALSE | MAY_BE_LONG),
F0("imagecolorresolvealpha", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
F0("imagecolorclosestalpha", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
F0("imagecolorexactalpha", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("imagecopyresampled", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
#ifdef PHP_WIN32
F1("imagegrabwindow", MAY_BE_FALSE | MAY_BE_RESOURCE),
F1("imagegrabscreen", MAY_BE_FALSE | MAY_BE_RESOURCE),
#endif
F1("imagerotate", MAY_BE_FALSE | MAY_BE_RESOURCE),
- F0("imagesettile", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagesetbrush", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
F1("imagecreate", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_RESOURCE),
- I0("imagetypes", MAY_BE_LONG),
F1("imagecreatefromstring", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_RESOURCE),
F1("imagecreatefromgif", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_RESOURCE),
#ifdef HAVE_GD_JPG
F1("imagecreatefromjpeg", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_RESOURCE),
- F0("imagejpeg", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("jpeg2wbmp", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
#endif
#ifdef HAVE_GD_PNG
F1("imagecreatefrompng", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_RESOURCE),
- F0("imagepng", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("png2wbmp", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
#endif
#ifdef HAVE_GD_WEBP
F1("imagecreatefromwebp", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_RESOURCE),
@@ -1542,70 +1177,26 @@ static const func_info_t func_infos[] = {
F1("imagecreatefromgd2part", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_RESOURCE),
#if defined(HAVE_GD_BMP)
F1("imagecreatefrombmp", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_RESOURCE),
- F0("imagebmp", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
#endif
- F0("imagexbm", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagegif", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagewbmp", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagegd", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagegd2", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagedestroy", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
F0("imagecolorallocate", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("imagepalettecopy", MAY_BE_NULL | MAY_BE_FALSE),
F0("imagecolorat", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
F0("imagecolorclosest", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
F0("imagecolorclosesthwb", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("imagecolordeallocate", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
F0("imagecolorresolve", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
F0("imagecolorexact", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
F0("imagecolorset", MAY_BE_NULL | MAY_BE_FALSE),
F1("imagecolorsforindex", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_LONG),
- F0("imagegammacorrect", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagesetpixel", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imageline", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagedashedline", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagerectangle", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagefilledrectangle", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagearc", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imageellipse", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagefilltoborder", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagefill", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagecolorstotal", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("imagecolortransparent", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("imageinterlace", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("imagepolygon", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imageopenpolygon", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagefilledpolygon", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagefontwidth", MAY_BE_NULL | MAY_BE_LONG),
- F0("imagefontheight", MAY_BE_NULL | MAY_BE_LONG),
- F0("imagechar", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagecharup", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagestring", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagestringup", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagecopy", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagecopymerge", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagecopymergegray", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagecopyresized", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagesx", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("imagesy", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("imagesetclip", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F1("imagegetclip", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_LONG),
+ F1("imagegetclip", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_LONG),
F1("imageftbbox", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_LONG),
F1("imagefttext", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_LONG),
F1("imagettfbbox", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_LONG),
F1("imagettftext", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_LONG),
- F0("image2wbmp", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagefilter", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imageconvolution", MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imageflip", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imageantialias", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
F1("imagecrop", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_RESOURCE),
F1("imagecropauto", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_RESOURCE),
F1("imagescale", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_RESOURCE),
F1("imageaffine", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_RESOURCE),
F1("imageaffinematrixget", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_DOUBLE),
F1("imageaffinematrixconcat", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_DOUBLE),
- F0("imagesetinterpolation", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
F1("imageresolution", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_LONG),
/* ext/spl */
@@ -1631,31 +1222,33 @@ uint32_t zend_get_func_info(const zend_call_info *call_info, const zend_ssa *ssa
if (callee_func->type == ZEND_INTERNAL_FUNCTION) {
zval *zv;
- func_info_t *info;
+ zend_string *lcname = Z_STR_P(CRT_CONSTANT_EX(call_info->caller_op_array, call_info->caller_init_opline, call_info->caller_init_opline->op2));
- zv = zend_hash_find_ex(&func_info, Z_STR_P(CRT_CONSTANT_EX(call_info->caller_op_array, call_info->caller_init_opline, call_info->caller_init_opline->op2, ssa->rt_constants)), 1);
+ zv = zend_hash_find_ex(&func_info, lcname, 1);
if (zv) {
- info = Z_PTR_P(zv);
+ func_info_t *info = Z_PTR_P(zv);
if (UNEXPECTED(zend_optimizer_is_disabled_func(info->name, info->name_len))) {
ret = MAY_BE_NULL;
} else if (info->info_func) {
ret = info->info_func(call_info, ssa);
- } else if (/*callee_func->common.arg_info && */
- callee_func->common.num_args == 0 &&
- callee_func->common.required_num_args == 0 &&
- !(callee_func->common.fn_flags & ZEND_ACC_VARIADIC)) {
- if (call_info->num_args == 0) {
- ret = info->info;
- } else {
- ret = FUNC_MAY_WARN | MAY_BE_NULL;
- }
} else {
ret = info->info;
}
-#if 0
+ return ret;
+ }
+
+ if (callee_func->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
+ zend_class_entry *ce; // TODO: Use the CE.
+ ret = zend_fetch_arg_info_type(NULL, callee_func->common.arg_info - 1, &ce);
} else {
+#if 0
fprintf(stderr, "Unknown internal function '%s'\n", func->common.function_name);
#endif
+ ret = MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF
+ | MAY_BE_RC1 | MAY_BE_RCN;
+ }
+ if (callee_func->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) {
+ ret |= MAY_BE_REF;
}
} else {
// FIXME: the order of functions matters!!!
@@ -1663,18 +1256,14 @@ uint32_t zend_get_func_info(const zend_call_info *call_info, const zend_ssa *ssa
if (info) {
ret = info->return_info.type;
}
- }
- if (!ret) {
- ret = MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
- if (callee_func->type == ZEND_INTERNAL_FUNCTION) {
- ret |= FUNC_MAY_WARN;
- }
- if (callee_func->common.fn_flags & ZEND_ACC_GENERATOR) {
- ret = MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_OBJECT;
- } else if (callee_func->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) {
- ret |= MAY_BE_REF;
- } else {
- ret |= MAY_BE_RC1 | MAY_BE_RCN;
+ if (!ret) {
+ ret = MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF
+ | MAY_BE_RC1 | MAY_BE_RCN;
+ /* For generators RETURN_REFERENCE refers to the yielded values. */
+ if ((callee_func->common.fn_flags & ZEND_ACC_RETURN_REFERENCE)
+ && !(callee_func->common.fn_flags & ZEND_ACC_GENERATOR)) {
+ ret |= MAY_BE_REF;
+ }
}
}
return ret;
diff --git a/ext/opcache/Optimizer/zend_func_info.h b/ext/opcache/Optimizer/zend_func_info.h
index 7eeb363da5..0f4fcea092 100644
--- a/ext/opcache/Optimizer/zend_func_info.h
+++ b/ext/opcache/Optimizer/zend_func_info.h
@@ -34,11 +34,6 @@
#define ZEND_FUNC_HAS_EXTENDED_FCALL (1<<10)
#define ZEND_FUNC_HAS_EXTENDED_STMT (1<<11)
-/* The following flags are valid only for return values of internal functions
- * returned by zend_get_func_info()
- */
-#define FUNC_MAY_WARN (1<<30)
-
typedef struct _zend_func_info zend_func_info;
typedef struct _zend_call_info zend_call_info;
diff --git a/ext/opcache/Optimizer/zend_inference.c b/ext/opcache/Optimizer/zend_inference.c
index f89b133b92..51872dcc61 100644
--- a/ext/opcache/Optimizer/zend_inference.c
+++ b/ext/opcache/Optimizer/zend_inference.c
@@ -1419,18 +1419,22 @@ int zend_inference_calc_range(const zend_op_array *op_array, zend_ssa *ssa, int
return 1;
} else if (op_array->arg_info &&
opline->op1.num <= op_array->num_args) {
- if (ZEND_TYPE_CODE(op_array->arg_info[opline->op1.num-1].type) == IS_LONG) {
- tmp->underflow = 0;
- tmp->min = ZEND_LONG_MIN;
- tmp->max = ZEND_LONG_MAX;
- tmp->overflow = 0;
- return 1;
- } else if (ZEND_TYPE_CODE(op_array->arg_info[opline->op1.num-1].type) == _IS_BOOL) {
- tmp->underflow = 0;
- tmp->min = 0;
- tmp->max = 1;
- tmp->overflow = 0;
- return 1;
+ zend_type type = op_array->arg_info[opline->op1.num-1].type;
+ if (ZEND_TYPE_IS_MASK(type)) {
+ uint32_t mask = ZEND_TYPE_MASK(ZEND_TYPE_WITHOUT_NULL(type));
+ if (mask == MAY_BE_LONG) {
+ tmp->underflow = 0;
+ tmp->min = ZEND_LONG_MIN;
+ tmp->max = ZEND_LONG_MAX;
+ tmp->overflow = 0;
+ return 1;
+ } else if (mask == (MAY_BE_FALSE|MAY_BE_TRUE)) {
+ tmp->underflow = 0;
+ tmp->min = 0;
+ tmp->max = 1;
+ tmp->overflow = 0;
+ return 1;
+ }
}
}
}
@@ -1833,9 +1837,7 @@ static int zend_infer_ranges(const zend_op_array *op_array, zend_ssa *ssa) /* {{
/* }}} */
static uint32_t get_ssa_alias_types(zend_ssa_alias_kind alias) {
- if (alias == PHP_ERRORMSG_ALIAS) {
- return MAY_BE_STRING | MAY_BE_RC1 | MAY_BE_RCN;
- } else if (alias == HTTP_RESPONSE_HEADER_ALIAS) {
+ if (alias == HTTP_RESPONSE_HEADER_ALIAS) {
return MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING | MAY_BE_RC1 | MAY_BE_RCN;
} else {
return MAY_BE_UNDEF | MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_REF | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
@@ -2063,16 +2065,10 @@ uint32_t zend_array_element_type(uint32_t t1, int write, int insert)
}
if (t1 & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE)) {
tmp |= MAY_BE_NULL;
- if (t1 & MAY_BE_ERROR) {
- if (write) {
- tmp |= MAY_BE_ERROR;
- }
- }
}
if (t1 & (MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE|MAY_BE_RESOURCE)) {
- tmp |= MAY_BE_NULL;
- if (write) {
- tmp |= MAY_BE_ERROR;
+ if (!write) {
+ tmp |= MAY_BE_NULL;
}
}
return tmp;
@@ -2234,25 +2230,26 @@ static inline zend_class_entry *get_class_entry(const zend_script *script, zend_
return NULL;
}
-static uint32_t zend_convert_type_code_to_may_be(zend_uchar type_code) {
- switch (type_code) {
- case IS_VOID:
- return MAY_BE_NULL;
- case IS_CALLABLE:
- return MAY_BE_STRING|MAY_BE_OBJECT|MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF;
- case IS_ITERABLE:
- return MAY_BE_OBJECT|MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF;
- case IS_ARRAY:
- return MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF;
- case _IS_BOOL:
- return MAY_BE_TRUE|MAY_BE_FALSE;
- default:
- ZEND_ASSERT(type_code < IS_REFERENCE);
- return 1 << type_code;
+static uint32_t zend_convert_type_declaration_mask(uint32_t type_mask) {
+ if (type_mask & MAY_BE_VOID) {
+ type_mask &= ~MAY_BE_VOID;
+ type_mask |= MAY_BE_NULL;
+ }
+ if (type_mask & MAY_BE_CALLABLE) {
+ type_mask &= ~MAY_BE_CALLABLE;
+ type_mask |= MAY_BE_STRING|MAY_BE_OBJECT|MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF;
+ }
+ if (type_mask & MAY_BE_ITERABLE) {
+ type_mask &= ~MAY_BE_ITERABLE;
+ type_mask |= MAY_BE_OBJECT|MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF;
+ }
+ if (type_mask & MAY_BE_ARRAY) {
+ type_mask |= MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF;
}
+ return type_mask;
}
-static uint32_t zend_fetch_arg_info(const zend_script *script, zend_arg_info *arg_info, zend_class_entry **pce)
+uint32_t zend_fetch_arg_info_type(const zend_script *script, zend_arg_info *arg_info, zend_class_entry **pce)
{
uint32_t tmp = 0;
@@ -2263,14 +2260,17 @@ static uint32_t zend_fetch_arg_info(const zend_script *script, zend_arg_info *ar
tmp |= MAY_BE_OBJECT;
*pce = get_class_entry(script, lcname);
zend_string_release_ex(lcname, 0);
- } else if (ZEND_TYPE_IS_CODE(arg_info->type)) {
- tmp |= zend_convert_type_code_to_may_be(ZEND_TYPE_CODE(arg_info->type));
+ } else if (ZEND_TYPE_IS_MASK(arg_info->type)) {
+ tmp |= zend_convert_type_declaration_mask(ZEND_TYPE_MASK(arg_info->type));
} else {
tmp |= MAY_BE_ANY|MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF;
}
if (ZEND_TYPE_ALLOW_NULL(arg_info->type)) {
tmp |= MAY_BE_NULL;
}
+ if (tmp & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
+ tmp |= MAY_BE_RC1 | MAY_BE_RCN;
+ }
return tmp;
}
@@ -2314,7 +2314,7 @@ static zend_property_info *zend_fetch_prop_info(const zend_op_array *op_array, z
}
if (ce) {
prop_info = lookup_prop_info(ce,
- Z_STR_P(CRT_CONSTANT_EX(op_array, opline, opline->op2, ssa->rt_constants)),
+ Z_STR_P(CRT_CONSTANT(opline->op2)),
op_array->scope);
if (prop_info && (prop_info->flags & ZEND_ACC_STATIC)) {
prop_info = NULL;
@@ -2345,12 +2345,12 @@ static zend_property_info *zend_fetch_static_prop_info(const zend_script *script
break;
}
} else if (opline->op2_type == IS_CONST) {
- zval *zv = CRT_CONSTANT_EX(op_array, opline, opline->op2, ssa->rt_constants);
+ zval *zv = CRT_CONSTANT(opline->op2);
ce = get_class_entry(script, Z_STR_P(zv + 1));
}
if (ce) {
- zval *zv = CRT_CONSTANT_EX(op_array, opline, opline->op1, ssa->rt_constants);
+ zval *zv = CRT_CONSTANT(opline->op1);
prop_info = lookup_prop_info(ce, Z_STR_P(zv), op_array->scope);
if (prop_info && !(prop_info->flags & ZEND_ACC_STATIC)) {
prop_info = NULL;
@@ -2365,7 +2365,7 @@ static uint32_t zend_fetch_prop_type(const zend_script *script, zend_property_in
if (prop_info && ZEND_TYPE_IS_SET(prop_info->type)) {
uint32_t type = ZEND_TYPE_IS_CLASS(prop_info->type)
? MAY_BE_OBJECT
- : zend_convert_type_code_to_may_be(ZEND_TYPE_CODE(prop_info->type));
+ : zend_convert_type_declaration_mask(ZEND_TYPE_MASK(prop_info->type));
if (ZEND_TYPE_ALLOW_NULL(prop_info->type)) {
type |= MAY_BE_NULL;
@@ -2419,8 +2419,8 @@ static int zend_update_type_info(const zend_op_array *op_array,
/* If one of the operands cannot have any type, this means the operand derives from
* unreachable code. Propagate the empty result early, so that that the following
* code may assume that operands have at least one type. */
- if (!(t1 & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_CLASS|MAY_BE_ERROR))
- || !(t2 & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_CLASS|MAY_BE_ERROR))) {
+ if (!(t1 & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_CLASS))
+ || !(t2 & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_CLASS))) {
tmp = 0;
if (ssa_ops[i].result_def >= 0) {
UPDATE_SSA_TYPE(tmp, ssa_ops[i].result_def);
@@ -2711,9 +2711,6 @@ static int zend_update_type_info(const zend_op_array *op_array,
tmp |= MAY_BE_LONG;
}
} else {
- if (t1 & MAY_BE_ERROR) {
- tmp |= MAY_BE_NULL;
- }
if (t1 & (MAY_BE_UNDEF | MAY_BE_NULL)) {
if (opline->opcode == ZEND_PRE_INC) {
tmp |= MAY_BE_LONG;
@@ -2746,7 +2743,7 @@ static int zend_update_type_info(const zend_op_array *op_array,
if (t1 & (MAY_BE_RC1|MAY_BE_RCN)) {
tmp |= MAY_BE_RC1|MAY_BE_RCN;
}
- tmp |= t1 & ~(MAY_BE_UNDEF|MAY_BE_ERROR|MAY_BE_REF|MAY_BE_RCN);
+ tmp |= t1 & ~(MAY_BE_UNDEF|MAY_BE_REF|MAY_BE_RCN);
if (t1 & MAY_BE_UNDEF) {
tmp |= MAY_BE_NULL;
}
@@ -2773,9 +2770,6 @@ static int zend_update_type_info(const zend_op_array *op_array,
tmp |= MAY_BE_LONG;
}
} else {
- if (t1 & MAY_BE_ERROR) {
- tmp |= MAY_BE_NULL;
- }
if (t1 & (MAY_BE_UNDEF | MAY_BE_NULL)) {
if (opline->opcode == ZEND_POST_INC) {
tmp |= MAY_BE_LONG;
@@ -2953,7 +2947,7 @@ static int zend_update_type_info(const zend_op_array *op_array,
if (opline->op2_type == IS_VAR && opline->extended_value == ZEND_RETURNS_FUNCTION) {
tmp = (MAY_BE_REF | MAY_BE_RCN | MAY_BE_RC1 | t2) & ~MAY_BE_UNDEF;
} else {
- tmp = (MAY_BE_REF | t2) & ~(MAY_BE_UNDEF|MAY_BE_ERROR|MAY_BE_RC1|MAY_BE_RCN);
+ tmp = (MAY_BE_REF | t2) & ~(MAY_BE_UNDEF|MAY_BE_RC1|MAY_BE_RCN);
}
if (t2 & MAY_BE_UNDEF) {
tmp |= MAY_BE_NULL;
@@ -2981,7 +2975,7 @@ static int zend_update_type_info(const zend_op_array *op_array,
if ((opline+1)->op1_type == IS_VAR && (opline->extended_value & ZEND_RETURNS_FUNCTION)) {
tmp = (MAY_BE_REF | MAY_BE_RCN | MAY_BE_RC1 | t2) & ~MAY_BE_UNDEF;
} else {
- tmp = (MAY_BE_REF | t2) & ~(MAY_BE_UNDEF|MAY_BE_ERROR|MAY_BE_RC1|MAY_BE_RCN);
+ tmp = (MAY_BE_REF | t2) & ~(MAY_BE_UNDEF|MAY_BE_RC1|MAY_BE_RCN);
}
if (t2 & MAY_BE_UNDEF) {
tmp |= MAY_BE_NULL;
@@ -3102,16 +3096,9 @@ static int zend_update_type_info(const zend_op_array *op_array,
ce = NULL;
if (arg_info) {
- tmp = zend_fetch_arg_info(script, arg_info, &ce);
- if (opline->opcode == ZEND_RECV_INIT &&
- Z_TYPE_P(CRT_CONSTANT_EX(op_array, opline, opline->op2, ssa->rt_constants)) == IS_CONSTANT_AST) {
- /* The constant may resolve to NULL */
- tmp |= MAY_BE_NULL;
- }
+ tmp = zend_fetch_arg_info_type(script, arg_info, &ce);
if (arg_info->pass_by_reference) {
tmp |= MAY_BE_REF;
- } else if (tmp & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
- tmp |= MAY_BE_RC1|MAY_BE_RCN;
}
} else {
tmp = MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_ANY|MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF;
@@ -3149,7 +3136,7 @@ static int zend_update_type_info(const zend_op_array *op_array,
}
case ZEND_DECLARE_ANON_CLASS:
UPDATE_SSA_TYPE(MAY_BE_CLASS, ssa_ops[i].result_def);
- if (script && (ce = zend_hash_find_ptr(&script->class_table, Z_STR_P(CRT_CONSTANT_EX(op_array, opline, opline->op1, ssa->rt_constants)))) != NULL) {
+ if (script && (ce = zend_hash_find_ptr(&script->class_table, Z_STR_P(CRT_CONSTANT(opline->op1)))) != NULL) {
UPDATE_SSA_OBJ_TYPE(ce, 0, ssa_ops[i].result_def);
}
break;
@@ -3177,7 +3164,7 @@ static int zend_update_type_info(const zend_op_array *op_array,
break;
}
} else if (opline->op2_type == IS_CONST) {
- zval *zv = CRT_CONSTANT_EX(op_array, opline, opline->op2, ssa->rt_constants);
+ zval *zv = CRT_CONSTANT(opline->op2);
if (Z_TYPE_P(zv) == IS_STRING) {
ce = get_class_entry(script, Z_STR_P(zv+1));
UPDATE_SSA_OBJ_TYPE(ce, 0, ssa_ops[i].result_def);
@@ -3191,7 +3178,7 @@ static int zend_update_type_info(const zend_op_array *op_array,
case ZEND_NEW:
tmp = MAY_BE_RC1|MAY_BE_RCN|MAY_BE_OBJECT;
if (opline->op1_type == IS_CONST &&
- (ce = get_class_entry(script, Z_STR_P(CRT_CONSTANT_EX(op_array, opline, opline->op1, ssa->rt_constants)+1))) != NULL) {
+ (ce = get_class_entry(script, Z_STR_P(CRT_CONSTANT(opline->op1)+1))) != NULL) {
UPDATE_SSA_OBJ_TYPE(ce, 0, ssa_ops[i].result_def);
} else if ((t1 & MAY_BE_CLASS) && ssa_ops[i].op1_use >= 0 && ssa_var_info[ssa_ops[i].op1_use].ce) {
UPDATE_SSA_OBJ_TYPE(ssa_var_info[ssa_ops[i].op1_use].ce, ssa_var_info[ssa_ops[i].op1_use].is_instanceof, ssa_ops[i].result_def);
@@ -3362,6 +3349,7 @@ static int zend_update_type_info(const zend_op_array *op_array,
case ZEND_FETCH_LIST_R:
case ZEND_FETCH_LIST_W:
if (ssa_ops[i].op1_def >= 0) {
+ uint32_t key_type = 0;
tmp = t1 & ~(MAY_BE_RC1|MAY_BE_RCN);
if (opline->opcode == ZEND_FETCH_DIM_W ||
opline->opcode == ZEND_FETCH_DIM_RW ||
@@ -3383,20 +3371,20 @@ static int zend_update_type_info(const zend_op_array *op_array,
tmp |= t1 & (MAY_BE_RC1|MAY_BE_RCN);
}
if (opline->op2_type == IS_UNUSED) {
- tmp |= MAY_BE_ARRAY_KEY_LONG;
+ key_type |= MAY_BE_ARRAY_KEY_LONG;
} else {
if (t2 & (MAY_BE_LONG|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_RESOURCE|MAY_BE_DOUBLE)) {
- tmp |= MAY_BE_ARRAY_KEY_LONG;
+ key_type |= MAY_BE_ARRAY_KEY_LONG;
}
if (t2 & MAY_BE_STRING) {
- tmp |= MAY_BE_ARRAY_KEY_STRING;
+ key_type |= MAY_BE_ARRAY_KEY_STRING;
if (opline->op2_type != IS_CONST) {
// FIXME: numeric string
- tmp |= MAY_BE_ARRAY_KEY_LONG;
+ key_type |= MAY_BE_ARRAY_KEY_LONG;
}
}
if (t2 & (MAY_BE_UNDEF | MAY_BE_NULL)) {
- tmp |= MAY_BE_ARRAY_KEY_STRING;
+ key_type |= MAY_BE_ARRAY_KEY_STRING;
}
}
} else if (opline->opcode == ZEND_FETCH_DIM_UNSET) {
@@ -3420,19 +3408,7 @@ static int zend_update_type_info(const zend_op_array *op_array,
case ZEND_FETCH_LIST_W:
case ZEND_ASSIGN_DIM:
case ZEND_ASSIGN_DIM_OP:
- tmp |= MAY_BE_ARRAY | MAY_BE_ARRAY_OF_ARRAY;
- break;
- case ZEND_FETCH_OBJ_W:
- case ZEND_FETCH_OBJ_RW:
- case ZEND_FETCH_OBJ_FUNC_ARG:
- case ZEND_ASSIGN_OBJ:
- case ZEND_ASSIGN_OBJ_OP:
- case ZEND_ASSIGN_OBJ_REF:
- case ZEND_PRE_INC_OBJ:
- case ZEND_PRE_DEC_OBJ:
- case ZEND_POST_INC_OBJ:
- case ZEND_POST_DEC_OBJ:
- tmp |= MAY_BE_ARRAY_OF_OBJECT;
+ tmp |= key_type | MAY_BE_ARRAY | MAY_BE_ARRAY_OF_ARRAY;
break;
case ZEND_SEND_VAR_EX:
case ZEND_SEND_FUNC_ARG:
@@ -3447,7 +3423,7 @@ static int zend_update_type_info(const zend_op_array *op_array,
case ZEND_VERIFY_RETURN_TYPE:
case ZEND_MAKE_REF:
case ZEND_FE_RESET_RW:
- tmp |= MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
+ tmp |= key_type | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
break;
case ZEND_PRE_INC:
case ZEND_PRE_DEC:
@@ -3455,11 +3431,24 @@ static int zend_update_type_info(const zend_op_array *op_array,
case ZEND_POST_DEC:
if (tmp & MAY_BE_ARRAY_OF_LONG) {
/* may overflow */
- tmp |= MAY_BE_ARRAY_OF_DOUBLE;
+ tmp |= key_type | MAY_BE_ARRAY_OF_DOUBLE;
} else if (!(tmp & (MAY_BE_ARRAY_OF_LONG|MAY_BE_ARRAY_OF_DOUBLE))) {
- tmp |= MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_DOUBLE;
+ tmp |= key_type | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_DOUBLE;
}
break;
+ case ZEND_FETCH_OBJ_W:
+ case ZEND_FETCH_OBJ_RW:
+ case ZEND_FETCH_OBJ_FUNC_ARG:
+ case ZEND_ASSIGN_OBJ:
+ case ZEND_ASSIGN_OBJ_OP:
+ case ZEND_ASSIGN_OBJ_REF:
+ case ZEND_PRE_INC_OBJ:
+ case ZEND_PRE_DEC_OBJ:
+ case ZEND_POST_INC_OBJ:
+ case ZEND_POST_DEC_OBJ:
+ /* These will result in an error exception, unless the element
+ * is already an object. */
+ break;
case ZEND_SEND_VAR:
/* This can occur if a DIM_FETCH_FUNC_ARG with UNUSED op2 is left
* behind, because it can't be converted to DIM_FETCH_R. */
@@ -3483,18 +3472,7 @@ static int zend_update_type_info(const zend_op_array *op_array,
opline->opcode != ZEND_FETCH_LIST_R ? t1 : ((t1 & ~MAY_BE_STRING) | MAY_BE_NULL),
opline->result_type == IS_VAR,
opline->op2_type == IS_UNUSED);
- if (opline->opcode == ZEND_FETCH_DIM_W ||
- opline->opcode == ZEND_FETCH_DIM_RW ||
- opline->opcode == ZEND_FETCH_DIM_FUNC_ARG ||
- opline->opcode == ZEND_FETCH_LIST_W) {
- if (t1 & (MAY_BE_ERROR|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE|MAY_BE_RESOURCE|MAY_BE_OBJECT)) {
- tmp |= MAY_BE_ERROR;
- } else if (opline->op2_type == IS_UNUSED) {
- tmp |= MAY_BE_ERROR;
- } else if (t2 & (MAY_BE_ARRAY|MAY_BE_OBJECT)) {
- tmp |= MAY_BE_ERROR;
- }
- } else if (opline->opcode == ZEND_FETCH_DIM_IS && (t1 & MAY_BE_STRING)) {
+ if (opline->opcode == ZEND_FETCH_DIM_IS && (t1 & MAY_BE_STRING)) {
tmp |= MAY_BE_NULL;
}
UPDATE_SSA_TYPE(tmp, ssa_ops[i].result_def);
@@ -3509,26 +3487,11 @@ static int zend_update_type_info(const zend_op_array *op_array,
case ZEND_FETCH_OBJ_W:
case ZEND_FETCH_OBJ_UNSET:
case ZEND_FETCH_OBJ_FUNC_ARG:
- if (ssa_ops[i].op1_def >= 0) {
- tmp = t1;
- if (opline->opcode == ZEND_FETCH_OBJ_W ||
- opline->opcode == ZEND_FETCH_OBJ_RW ||
- opline->opcode == ZEND_FETCH_OBJ_FUNC_ARG) {
- if (opline->opcode != ZEND_FETCH_DIM_FUNC_ARG) {
- if (t1 & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE)) {
- tmp &= ~(MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE);
- tmp |= MAY_BE_OBJECT | MAY_BE_RC1 | MAY_BE_RCN;
- }
- }
- }
- UPDATE_SSA_TYPE(tmp, ssa_ops[i].op1_def);
- COPY_SSA_OBJ_TYPE(ssa_ops[i].op1_use, ssa_ops[i].op1_def);
- }
if (ssa_ops[i].result_def >= 0) {
tmp = zend_fetch_prop_type(script,
zend_fetch_prop_info(op_array, ssa, opline, i), &ce);
if (opline->result_type != IS_TMP_VAR) {
- tmp |= MAY_BE_REF | MAY_BE_ERROR;
+ tmp |= MAY_BE_REF;
}
UPDATE_SSA_TYPE(tmp, ssa_ops[i].result_def);
if (ce) {
@@ -3545,7 +3508,7 @@ static int zend_update_type_info(const zend_op_array *op_array,
tmp = zend_fetch_prop_type(script,
zend_fetch_static_prop_info(script, op_array, ssa, opline), &ce);
if (opline->result_type != IS_TMP_VAR) {
- tmp |= MAY_BE_REF | MAY_BE_ERROR;
+ tmp |= MAY_BE_REF;
}
UPDATE_SSA_TYPE(tmp, ssa_ops[i].result_def);
if (ce) {
@@ -3567,7 +3530,7 @@ static int zend_update_type_info(const zend_op_array *op_array,
if (!call_info) {
goto unknown_opcode;
}
- tmp = zend_get_func_info(call_info, ssa) & ~FUNC_MAY_WARN;
+ tmp = zend_get_func_info(call_info, ssa);
UPDATE_SSA_TYPE(tmp, ssa_ops[i].result_def);
if (call_info->callee_func->type == ZEND_USER_FUNCTION) {
func_info = ZEND_FUNC_INFO(&call_info->callee_func->op_array);
@@ -3615,11 +3578,7 @@ static int zend_update_type_info(const zend_op_array *op_array,
ce = NULL;
} else {
zend_arg_info *ret_info = op_array->arg_info - 1;
-
- tmp = zend_fetch_arg_info(script, ret_info, &ce);
- if (tmp & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
- tmp |= MAY_BE_RC1 | MAY_BE_RCN;
- }
+ tmp = zend_fetch_arg_info_type(script, ret_info, &ce);
}
if (opline->op1_type & (IS_TMP_VAR|IS_VAR|IS_CV)) {
UPDATE_SSA_TYPE(tmp, ssa_ops[i].op1_def);
@@ -3886,7 +3845,7 @@ static zend_bool can_convert_to_double(
ZVAL_COPY_VALUE(&orig_op1, value);
ZVAL_DOUBLE(&dval_op1, (double) Z_LVAL_P(value));
} else if (opline->op1_type == IS_CONST) {
- zval *zv = CRT_CONSTANT_EX(op_array, opline, opline->op1, ssa->rt_constants);
+ zval *zv = CRT_CONSTANT(opline->op1);
if (Z_TYPE_P(zv) == IS_LONG || Z_TYPE_P(zv) == IS_DOUBLE) {
ZVAL_COPY_VALUE(&orig_op1, zv);
ZVAL_COPY_VALUE(&dval_op1, zv);
@@ -3899,7 +3858,7 @@ static zend_bool can_convert_to_double(
ZVAL_COPY_VALUE(&orig_op2, value);
ZVAL_DOUBLE(&dval_op2, (double) Z_LVAL_P(value));
} else if (opline->op2_type == IS_CONST) {
- zval *zv = CRT_CONSTANT_EX(op_array, opline, opline->op2, ssa->rt_constants);
+ zval *zv = CRT_CONSTANT(opline->op2);
if (Z_TYPE_P(zv) == IS_LONG || Z_TYPE_P(zv) == IS_DOUBLE) {
ZVAL_COPY_VALUE(&orig_op2, zv);
ZVAL_COPY_VALUE(&dval_op2, zv);
@@ -3987,7 +3946,7 @@ static int zend_type_narrowing(const zend_op_array *op_array, const zend_script
* doubles instead, in the hope that we'll narrow long|double to double. */
if (opline->opcode == ZEND_ASSIGN && opline->result_type == IS_UNUSED &&
opline->op1_type == IS_CV && opline->op2_type == IS_CONST) {
- zval *value = CRT_CONSTANT_EX(op_array, opline, opline->op2, ssa->rt_constants);
+ zval *value = CRT_CONSTANT(opline->op2);
zend_bitset_clear(visited, bitset_len);
if (can_convert_to_double(op_array, ssa, v, value, visited)) {
@@ -4046,11 +4005,9 @@ void zend_init_func_return_info(const zend_op_array *op_array,
zend_arg_info *ret_info = op_array->arg_info - 1;
zend_ssa_range tmp_range = {0, 0, 0, 0};
- ret->type = zend_fetch_arg_info(script, ret_info, &ret->ce);
+ ret->type = zend_fetch_arg_info_type(script, ret_info, &ret->ce);
if (op_array->fn_flags & ZEND_ACC_RETURN_REFERENCE) {
ret->type |= MAY_BE_REF;
- } else if (ret->type & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
- ret->type |= MAY_BE_RC1|MAY_BE_RCN;
}
ret->is_instanceof = (ret->ce) ? 1 : 0;
ret->range = tmp_range;
@@ -4141,7 +4098,7 @@ void zend_func_return_info(const zend_op_array *op_array,
}
if (opline->op1_type == IS_CONST) {
- zval *zv = CRT_CONSTANT_EX(op_array, opline, opline->op1, info->ssa.rt_constants);
+ zval *zv = CRT_CONSTANT(opline->op1);
if (Z_TYPE_P(zv) == IS_NULL) {
if (tmp_has_range < 0) {
@@ -4363,7 +4320,7 @@ void zend_inference_check_recursive_dependencies(zend_op_array *op_array)
free_alloca(worklist, use_heap);
}
-int zend_may_throw(const zend_op *opline, zend_op_array *op_array, zend_ssa *ssa)
+int zend_may_throw(const zend_op *opline, const zend_op_array *op_array, zend_ssa *ssa)
{
uint32_t t1 = OP1_INFO();
uint32_t t2 = OP2_INFO();
@@ -4620,7 +4577,7 @@ int zend_may_throw(const zend_op *opline, zend_op_array *op_array, zend_ssa *ssa
if (opline->op2_type == IS_CONST) {
prop_info = zend_hash_find_ptr(&ce->properties_info,
- Z_STR_P(CRT_CONSTANT_EX(op_array, opline, opline->op2, ssa->rt_constants)));
+ Z_STR_P(CRT_CONSTANT(opline->op2)));
if (prop_info && !(prop_info->flags & ZEND_ACC_PUBLIC)) {
return 1;
}
@@ -4650,7 +4607,7 @@ int zend_may_throw(const zend_op *opline, zend_op_array *op_array, zend_ssa *ssa
case ZEND_COUNT:
return (t1 & MAY_BE_ANY) != MAY_BE_ARRAY;
case ZEND_RECV_INIT:
- if (Z_TYPE_P(CRT_CONSTANT_EX(op_array, opline, opline->op2, ssa->rt_constants)) == IS_CONSTANT_AST) {
+ if (Z_TYPE_P(CRT_CONSTANT(opline->op2)) == IS_CONSTANT_AST) {
return 1;
}
if (op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) {
diff --git a/ext/opcache/Optimizer/zend_inference.h b/ext/opcache/Optimizer/zend_inference.h
index ec98fcbef9..f01f6cc786 100644
--- a/ext/opcache/Optimizer/zend_inference.h
+++ b/ext/opcache/Optimizer/zend_inference.h
@@ -26,11 +26,11 @@
/* Bitmask for type inference (zend_ssa_var_info.type) */
#include "zend_type_info.h"
-#define MAY_BE_IN_REG (1<<25) /* value allocated in CPU register */
+#define MAY_BE_IN_REG (1<<29) /* value allocated in CPU register */
//TODO: remome MAY_BE_RC1, MAY_BE_RCN???
-#define MAY_BE_RC1 (1<<27) /* may be non-reference with refcount == 1 */
-#define MAY_BE_RCN (1<<28) /* may be non-reference with refcount > 1 */
+#define MAY_BE_RC1 (1<<30) /* may be non-reference with refcount == 1 */
+#define MAY_BE_RCN (1u<<31) /* may be non-reference with refcount > 1 */
#define MAY_HAVE_DTOR \
(MAY_BE_OBJECT|MAY_BE_RESOURCE \
@@ -40,7 +40,7 @@
static zend_always_inline zend_bool _ssa_##opN##_has_range(const zend_op_array *op_array, const zend_ssa *ssa, const zend_op *opline) \
{ \
if (opline->opN##_type == IS_CONST) { \
- zval *zv = CRT_CONSTANT_EX(op_array, opline, opline->opN, ssa->rt_constants); \
+ zval *zv = CRT_CONSTANT(opline->opN); \
return (Z_TYPE_P(zv) == IS_LONG || Z_TYPE_P(zv) == IS_TRUE || Z_TYPE_P(zv) == IS_FALSE || Z_TYPE_P(zv) == IS_NULL); \
} else { \
return (opline->opN##_type != IS_UNUSED && \
@@ -56,7 +56,7 @@
static zend_always_inline zend_long _ssa_##opN##_min_range(const zend_op_array *op_array, const zend_ssa *ssa, const zend_op *opline) \
{ \
if (opline->opN##_type == IS_CONST) { \
- zval *zv = CRT_CONSTANT_EX(op_array, opline, opline->opN, ssa->rt_constants); \
+ zval *zv = CRT_CONSTANT(opline->opN); \
if (Z_TYPE_P(zv) == IS_LONG) { \
return Z_LVAL_P(zv); \
} else if (Z_TYPE_P(zv) == IS_TRUE) { \
@@ -80,7 +80,7 @@
static zend_always_inline zend_long _ssa_##opN##_max_range(const zend_op_array *op_array, const zend_ssa *ssa, const zend_op *opline) \
{ \
if (opline->opN##_type == IS_CONST) { \
- zval *zv = CRT_CONSTANT_EX(op_array, opline, opline->opN, ssa->rt_constants); \
+ zval *zv = CRT_CONSTANT(opline->opN); \
if (Z_TYPE_P(zv) == IS_LONG) { \
return Z_LVAL_P(zv); \
} else if (Z_TYPE_P(zv) == IS_TRUE) { \
@@ -104,7 +104,7 @@
static zend_always_inline char _ssa_##opN##_range_underflow(const zend_op_array *op_array, const zend_ssa *ssa, const zend_op *opline) \
{ \
if (opline->opN##_type == IS_CONST) { \
- zval *zv = CRT_CONSTANT_EX(op_array, opline, opline->opN, ssa->rt_constants); \
+ zval *zv = CRT_CONSTANT(opline->opN); \
if (Z_TYPE_P(zv) == IS_LONG || Z_TYPE_P(zv) == IS_TRUE || Z_TYPE_P(zv) == IS_FALSE || Z_TYPE_P(zv) == IS_NULL) { \
return 0; \
} \
@@ -122,7 +122,7 @@
static zend_always_inline char _ssa_##opN##_range_overflow(const zend_op_array *op_array, const zend_ssa *ssa, const zend_op *opline) \
{ \
if (opline->opN##_type == IS_CONST) { \
- zval *zv = CRT_CONSTANT_EX(op_array, opline, opline->opN, ssa->rt_constants); \
+ zval *zv = CRT_CONSTANT(opline->opN); \
if (Z_TYPE_P(zv) == IS_LONG || Z_TYPE_P(zv) == IS_TRUE || Z_TYPE_P(zv) == IS_FALSE || Z_TYPE_P(zv) == IS_NULL) { \
return 0; \
} \
@@ -199,7 +199,7 @@ static zend_always_inline uint32_t get_ssa_var_info(const zend_ssa *ssa, int ssa
if (ssa->var_info && ssa_var_num >= 0) {
return ssa->var_info[ssa_var_num].type;
} else {
- return MAY_BE_UNDEF | MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_REF | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ERROR;
+ return MAY_BE_UNDEF | MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_REF | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
}
}
@@ -207,7 +207,7 @@ static zend_always_inline uint32_t get_ssa_var_info(const zend_ssa *ssa, int ssa
static zend_always_inline uint32_t _ssa_##opN##_info(const zend_op_array *op_array, const zend_ssa *ssa, const zend_op *opline) \
{ \
if (opline->opN##_type == IS_CONST) { \
- return _const_op_type(CRT_CONSTANT_EX(op_array, opline, opline->opN, ssa->rt_constants)); \
+ return _const_op_type(CRT_CONSTANT(opline->opN)); \
} else { \
return get_ssa_var_info(ssa, ssa->ops ? ssa->ops[opline - op_array->opcodes].opN##_use : -1); \
} \
@@ -263,6 +263,8 @@ void zend_inference_check_recursive_dependencies(zend_op_array *op_array);
int zend_infer_types_ex(const zend_op_array *op_array, const zend_script *script, zend_ssa *ssa, zend_bitset worklist, zend_long optimization_level);
+uint32_t zend_fetch_arg_info_type(
+ const zend_script *script, zend_arg_info *arg_info, zend_class_entry **pce);
void zend_init_func_return_info(const zend_op_array *op_array,
const zend_script *script,
zend_ssa_var_info *ret);
@@ -272,7 +274,7 @@ void zend_func_return_info(const zend_op_array *op_array,
int widening,
zend_ssa_var_info *ret);
-int zend_may_throw(const zend_op *opline, zend_op_array *op_array, zend_ssa *ssa);
+int zend_may_throw(const zend_op *opline, const zend_op_array *op_array, zend_ssa *ssa);
END_EXTERN_C()
diff --git a/ext/opcache/Optimizer/zend_optimizer.c b/ext/opcache/Optimizer/zend_optimizer.c
index a922d0f597..aa638032ca 100644
--- a/ext/opcache/Optimizer/zend_optimizer.c
+++ b/ext/opcache/Optimizer/zend_optimizer.c
@@ -32,10 +32,6 @@
#include "zend_inference.h"
#include "zend_dump.h"
-#ifndef HAVE_DFA_PASS
-# define HAVE_DFA_PASS 1
-#endif
-
static void zend_optimizer_zval_dtor_wrapper(zval *zvalue)
{
zval_ptr_dtor_nogc(zvalue);
@@ -657,8 +653,8 @@ int zend_optimizer_replace_by_const(zend_op_array *op_array,
case ZEND_VERIFY_RETURN_TYPE: {
zend_arg_info *ret_info = op_array->arg_info - 1;
if (ZEND_TYPE_IS_CLASS(ret_info->type)
- || ZEND_TYPE_CODE(ret_info->type) == IS_CALLABLE
- || !ZEND_SAME_FAKE_TYPE(ZEND_TYPE_CODE(ret_info->type), Z_TYPE_P(val))
+ || (ZEND_TYPE_IS_MASK(ret_info->type)
+ && !ZEND_TYPE_CONTAINS_CODE(ret_info->type, Z_TYPE_P(val)))
|| (op_array->fn_flags & ZEND_ACC_RETURN_REFERENCE)) {
return 0;
}
@@ -777,9 +773,9 @@ void zend_optimizer_shift_jump(zend_op_array *op_array, zend_op *opline, uint32_
}
static zend_class_entry *get_class_entry_from_op1(
- zend_script *script, zend_op_array *op_array, zend_op *opline, zend_bool rt_constants) {
+ zend_script *script, zend_op_array *op_array, zend_op *opline) {
if (opline->op1_type == IS_CONST) {
- zval *op1 = CRT_CONSTANT_EX(op_array, opline, opline->op1, rt_constants);
+ zval *op1 = CRT_CONSTANT(opline->op1);
if (Z_TYPE_P(op1) == IS_STRING) {
zend_string *class_name = Z_STR_P(op1 + 1);
zend_class_entry *ce;
@@ -804,13 +800,12 @@ static zend_class_entry *get_class_entry_from_op1(
}
zend_function *zend_optimizer_get_called_func(
- zend_script *script, zend_op_array *op_array, zend_op *opline, zend_bool rt_constants)
+ zend_script *script, zend_op_array *op_array, zend_op *opline)
{
-#define GET_OP(op) CRT_CONSTANT_EX(op_array, opline, opline->op, rt_constants)
switch (opline->opcode) {
case ZEND_INIT_FCALL:
{
- zend_string *function_name = Z_STR_P(GET_OP(op2));
+ zend_string *function_name = Z_STR_P(CRT_CONSTANT(opline->op2));
zend_function *func;
if (script && (func = zend_hash_find_ptr(&script->function_table, function_name)) != NULL) {
return func;
@@ -827,8 +822,8 @@ zend_function *zend_optimizer_get_called_func(
}
case ZEND_INIT_FCALL_BY_NAME:
case ZEND_INIT_NS_FCALL_BY_NAME:
- if (opline->op2_type == IS_CONST && Z_TYPE_P(GET_OP(op2)) == IS_STRING) {
- zval *function_name = GET_OP(op2) + 1;
+ if (opline->op2_type == IS_CONST && Z_TYPE_P(CRT_CONSTANT(opline->op2)) == IS_STRING) {
+ zval *function_name = CRT_CONSTANT(opline->op2) + 1;
zend_function *func;
if (script && (func = zend_hash_find_ptr(&script->function_table, Z_STR_P(function_name)))) {
return func;
@@ -844,11 +839,11 @@ zend_function *zend_optimizer_get_called_func(
}
break;
case ZEND_INIT_STATIC_METHOD_CALL:
- if (opline->op2_type == IS_CONST && Z_TYPE_P(GET_OP(op2)) == IS_STRING) {
+ if (opline->op2_type == IS_CONST && Z_TYPE_P(CRT_CONSTANT(opline->op2)) == IS_STRING) {
zend_class_entry *ce = get_class_entry_from_op1(
- script, op_array, opline, rt_constants);
+ script, op_array, opline);
if (ce) {
- zend_string *func_name = Z_STR_P(GET_OP(op2) + 1);
+ zend_string *func_name = Z_STR_P(CRT_CONSTANT(opline->op2) + 1);
zend_function *fbc = zend_hash_find_ptr(&ce->function_table, func_name);
if (fbc) {
zend_bool is_public = (fbc->common.fn_flags & ZEND_ACC_PUBLIC) != 0;
@@ -862,9 +857,9 @@ zend_function *zend_optimizer_get_called_func(
break;
case ZEND_INIT_METHOD_CALL:
if (opline->op1_type == IS_UNUSED
- && opline->op2_type == IS_CONST && Z_TYPE_P(GET_OP(op2)) == IS_STRING
+ && opline->op2_type == IS_CONST && Z_TYPE_P(CRT_CONSTANT(opline->op2)) == IS_STRING
&& op_array->scope && !(op_array->scope->ce_flags & ZEND_ACC_TRAIT)) {
- zend_string *method_name = Z_STR_P(GET_OP(op2) + 1);
+ zend_string *method_name = Z_STR_P(CRT_CONSTANT(opline->op2) + 1);
zend_function *fbc = zend_hash_find_ptr(
&op_array->scope->function_table, method_name);
if (fbc) {
@@ -881,7 +876,7 @@ zend_function *zend_optimizer_get_called_func(
case ZEND_NEW:
{
zend_class_entry *ce = get_class_entry_from_op1(
- script, op_array, opline, rt_constants);
+ script, op_array, opline);
if (ce && ce->type == ZEND_USER_CLASS) {
return ce->constructor;
}
@@ -889,7 +884,6 @@ zend_function *zend_optimizer_get_called_func(
}
}
return NULL;
-#undef GET_OP
}
uint32_t zend_optimizer_classify_function(zend_string *name, uint32_t num_args) {
@@ -897,14 +891,8 @@ uint32_t zend_optimizer_classify_function(zend_string *name, uint32_t num_args)
return ZEND_FUNC_INDIRECT_VAR_ACCESS;
} else if (zend_string_equals_literal(name, "compact")) {
return ZEND_FUNC_INDIRECT_VAR_ACCESS;
- } else if (zend_string_equals_literal(name, "parse_str") && num_args <= 1) {
- return ZEND_FUNC_INDIRECT_VAR_ACCESS;
- } else if (zend_string_equals_literal(name, "mb_parse_str") && num_args <= 1) {
- return ZEND_FUNC_INDIRECT_VAR_ACCESS;
} else if (zend_string_equals_literal(name, "get_defined_vars")) {
return ZEND_FUNC_INDIRECT_VAR_ACCESS;
- } else if (zend_string_equals_literal(name, "assert")) {
- return ZEND_FUNC_INDIRECT_VAR_ACCESS;
} else if (zend_string_equals_literal(name, "func_num_args")) {
return ZEND_FUNC_VARARG;
} else if (zend_string_equals_literal(name, "func_get_arg")) {
@@ -940,12 +928,13 @@ static void zend_optimize(zend_op_array *op_array,
zend_dump_op_array(op_array, ZEND_DUMP_LIVE_RANGES, "before optimizer", NULL);
}
- /* pass 1
- * - substitute persistent constants (true, false, null, etc)
- * - perform compile-time evaluation of constant binary and unary operations
- * - optimize series of ADD_STRING and/or ADD_CHAR
- * - convert CAST(IS_BOOL,x) into BOOL(x)
- * - pre-evaluate constant function calls
+ /* pass 1 (Simple local optimizations)
+ * - persistent constant substitution (true, false, null, etc)
+ * - constant casting (ADD expects numbers, CONCAT strings, etc)
+ * - constant expression evaluation
+ * - optimize constant conditional JMPs
+ * - pre-evaluate constant function calls
+ * - eliminate FETCH $GLOBALS followed by FETCH_DIM/UNSET_DIM/ISSET_ISEMPTY_DIM
*/
if (ZEND_OPTIMIZER_PASS_1 & ctx->optimization_level) {
zend_optimizer_pass1(op_array, ctx);
@@ -954,21 +943,8 @@ static void zend_optimize(zend_op_array *op_array,
}
}
- /* pass 2:
- * - convert non-numeric constants to numeric constants in numeric operators
- * - optimize constant conditional JMPs
- */
- if (ZEND_OPTIMIZER_PASS_2 & ctx->optimization_level) {
- zend_optimizer_pass2(op_array);
- if (ctx->debug_level & ZEND_DUMP_AFTER_PASS_2) {
- zend_dump_op_array(op_array, 0, "after pass 2", NULL);
- }
- }
-
- /* pass 3:
- * - optimize $i = $i+expr to $i+=expr
+ /* pass 3: (Jump optimization)
* - optimize series of JMPs
- * - change $i++ to ++$i where possible
*/
if (ZEND_OPTIMIZER_PASS_3 & ctx->optimization_level) {
zend_optimizer_pass3(op_array, ctx);
@@ -997,7 +973,6 @@ static void zend_optimize(zend_op_array *op_array,
}
}
-#if HAVE_DFA_PASS
/* pass 6:
* - DFA optimization
*/
@@ -1008,7 +983,6 @@ static void zend_optimize(zend_op_array *op_array,
zend_dump_op_array(op_array, 0, "after pass 6", NULL);
}
}
-#endif
/* pass 9:
* - Optimize temp variables usage
@@ -1064,6 +1038,8 @@ static void zend_revert_pass_two(zend_op_array *op_array)
{
zend_op *opline, *end;
+ ZEND_ASSERT((op_array->fn_flags & ZEND_ACC_DONE_PASS_TWO) != 0);
+
opline = op_array->opcodes;
end = opline + op_array->last;
while (opline < end) {
@@ -1073,6 +1049,8 @@ static void zend_revert_pass_two(zend_op_array *op_array)
if (opline->op2_type == IS_CONST) {
ZEND_PASS_TWO_UNDO_CONSTANT(op_array, opline, opline->op2);
}
+ /* reset smart branch flags IS_SMART_BRANCH_JMP[N]Z */
+ opline->result_type &= (IS_TMP_VAR|IS_VAR|IS_CV|IS_CONST);
opline++;
}
#if !ZEND_USE_ABS_CONST_ADDR
@@ -1082,6 +1060,8 @@ static void zend_revert_pass_two(zend_op_array *op_array)
op_array->literals = literals;
}
#endif
+
+ op_array->fn_flags &= ~ZEND_ACC_DONE_PASS_TWO;
}
static void zend_redo_pass_two(zend_op_array *op_array)
@@ -1091,6 +1071,8 @@ static void zend_redo_pass_two(zend_op_array *op_array)
zend_op *old_opcodes = op_array->opcodes;
#endif
+ ZEND_ASSERT((op_array->fn_flags & ZEND_ACC_DONE_PASS_TWO) == 0);
+
#if !ZEND_USE_ABS_CONST_ADDR
if (op_array->last_literal) {
op_array->opcodes = (zend_op *) erealloc(op_array->opcodes,
@@ -1117,48 +1099,79 @@ static void zend_redo_pass_two(zend_op_array *op_array)
if (opline->op2_type == IS_CONST) {
ZEND_PASS_TWO_UPDATE_CONSTANT(op_array, opline, opline->op2);
}
+ /* fix jumps to point to new array */
+ switch (opline->opcode) {
#if ZEND_USE_ABS_JMP_ADDR && !ZEND_USE_ABS_CONST_ADDR
- if (op_array->fn_flags & ZEND_ACC_DONE_PASS_TWO) {
- /* fix jumps to point to new array */
- switch (opline->opcode) {
- case ZEND_JMP:
- case ZEND_FAST_CALL:
- opline->op1.jmp_addr = &op_array->opcodes[opline->op1.jmp_addr - old_opcodes];
- break;
- case ZEND_JMPZNZ:
- /* relative extended_value don't have to be changed */
- /* break omitted intentionally */
- case ZEND_JMPZ:
- case ZEND_JMPNZ:
- case ZEND_JMPZ_EX:
- case ZEND_JMPNZ_EX:
- case ZEND_JMP_SET:
- case ZEND_COALESCE:
- case ZEND_FE_RESET_R:
- case ZEND_FE_RESET_RW:
- case ZEND_ASSERT_CHECK:
+ case ZEND_JMP:
+ case ZEND_FAST_CALL:
+ opline->op1.jmp_addr = &op_array->opcodes[opline->op1.jmp_addr - old_opcodes];
+ break;
+ case ZEND_JMPZNZ:
+ /* relative extended_value don't have to be changed */
+ /* break omitted intentionally */
+ case ZEND_JMPZ:
+ case ZEND_JMPNZ:
+ case ZEND_JMPZ_EX:
+ case ZEND_JMPNZ_EX:
+ case ZEND_JMP_SET:
+ case ZEND_COALESCE:
+ case ZEND_FE_RESET_R:
+ case ZEND_FE_RESET_RW:
+ case ZEND_ASSERT_CHECK:
+ opline->op2.jmp_addr = &op_array->opcodes[opline->op2.jmp_addr - old_opcodes];
+ break;
+ case ZEND_CATCH:
+ if (!(opline->extended_value & ZEND_LAST_CATCH)) {
opline->op2.jmp_addr = &op_array->opcodes[opline->op2.jmp_addr - old_opcodes];
- break;
- case ZEND_CATCH:
- if (!(opline->extended_value & ZEND_LAST_CATCH)) {
- opline->op2.jmp_addr = &op_array->opcodes[opline->op2.jmp_addr - old_opcodes];
+ }
+ break;
+ case ZEND_FE_FETCH_R:
+ case ZEND_FE_FETCH_RW:
+ case ZEND_SWITCH_LONG:
+ case ZEND_SWITCH_STRING:
+ /* relative extended_value don't have to be changed */
+ break;
+#endif
+ case ZEND_IS_IDENTICAL:
+ case ZEND_IS_NOT_IDENTICAL:
+ case ZEND_IS_EQUAL:
+ case ZEND_IS_NOT_EQUAL:
+ case ZEND_IS_SMALLER:
+ case ZEND_IS_SMALLER_OR_EQUAL:
+ case ZEND_CASE:
+ case ZEND_ISSET_ISEMPTY_CV:
+ case ZEND_ISSET_ISEMPTY_VAR:
+ case ZEND_ISSET_ISEMPTY_DIM_OBJ:
+ case ZEND_ISSET_ISEMPTY_PROP_OBJ:
+ case ZEND_ISSET_ISEMPTY_STATIC_PROP:
+ case ZEND_INSTANCEOF:
+ case ZEND_TYPE_CHECK:
+ case ZEND_DEFINED:
+ case ZEND_IN_ARRAY:
+ case ZEND_ARRAY_KEY_EXISTS:
+ if (opline->result_type & IS_TMP_VAR) {
+ /* reinitialize result_type of smart branch instructions */
+ if (opline + 1 < end) {
+ if ((opline+1)->opcode == ZEND_JMPZ
+ && (opline+1)->op1_type == IS_TMP_VAR
+ && (opline+1)->op1.var == opline->result.var) {
+ opline->result_type = IS_SMART_BRANCH_JMPZ | IS_TMP_VAR;
+ } else if ((opline+1)->opcode == ZEND_JMPNZ
+ && (opline+1)->op1_type == IS_TMP_VAR
+ && (opline+1)->op1.var == opline->result.var) {
+ opline->result_type = IS_SMART_BRANCH_JMPNZ | IS_TMP_VAR;
+ }
}
- break;
- case ZEND_FE_FETCH_R:
- case ZEND_FE_FETCH_RW:
- case ZEND_SWITCH_LONG:
- case ZEND_SWITCH_STRING:
- /* relative extended_value don't have to be changed */
- break;
- }
+ }
+ break;
}
-#endif
ZEND_VM_SET_OPCODE_HANDLER(opline);
opline++;
}
+
+ op_array->fn_flags |= ZEND_ACC_DONE_PASS_TWO;
}
-#if HAVE_DFA_PASS
static void zend_redo_pass_two_ex(zend_op_array *op_array, zend_ssa *ssa)
{
zend_op *opline, *end;
@@ -1166,6 +1179,8 @@ static void zend_redo_pass_two_ex(zend_op_array *op_array, zend_ssa *ssa)
zend_op *old_opcodes = op_array->opcodes;
#endif
+ ZEND_ASSERT((op_array->fn_flags & ZEND_ACC_DONE_PASS_TWO) == 0);
+
#if !ZEND_USE_ABS_CONST_ADDR
if (op_array->last_literal) {
op_array->opcodes = (zend_op *) erealloc(op_array->opcodes,
@@ -1203,47 +1218,78 @@ static void zend_redo_pass_two_ex(zend_op_array *op_array, zend_ssa *ssa)
ZEND_PASS_TWO_UPDATE_CONSTANT(op_array, opline, opline->op2);
}
- zend_vm_set_opcode_handler_ex(opline, op1_info, op2_info, res_info);
+ /* fix jumps to point to new array */
+ switch (opline->opcode) {
#if ZEND_USE_ABS_JMP_ADDR && !ZEND_USE_ABS_CONST_ADDR
- if (op_array->fn_flags & ZEND_ACC_DONE_PASS_TWO) {
- /* fix jumps to point to new array */
- switch (opline->opcode) {
- case ZEND_JMP:
- case ZEND_FAST_CALL:
- opline->op1.jmp_addr = &op_array->opcodes[opline->op1.jmp_addr - old_opcodes];
- break;
- case ZEND_JMPZNZ:
- /* relative extended_value don't have to be changed */
- /* break omitted intentionally */
- case ZEND_JMPZ:
- case ZEND_JMPNZ:
- case ZEND_JMPZ_EX:
- case ZEND_JMPNZ_EX:
- case ZEND_JMP_SET:
- case ZEND_COALESCE:
- case ZEND_FE_RESET_R:
- case ZEND_FE_RESET_RW:
- case ZEND_ASSERT_CHECK:
+ case ZEND_JMP:
+ case ZEND_FAST_CALL:
+ opline->op1.jmp_addr = &op_array->opcodes[opline->op1.jmp_addr - old_opcodes];
+ break;
+ case ZEND_JMPZNZ:
+ /* relative extended_value don't have to be changed */
+ /* break omitted intentionally */
+ case ZEND_JMPZ:
+ case ZEND_JMPNZ:
+ case ZEND_JMPZ_EX:
+ case ZEND_JMPNZ_EX:
+ case ZEND_JMP_SET:
+ case ZEND_COALESCE:
+ case ZEND_FE_RESET_R:
+ case ZEND_FE_RESET_RW:
+ case ZEND_ASSERT_CHECK:
+ opline->op2.jmp_addr = &op_array->opcodes[opline->op2.jmp_addr - old_opcodes];
+ break;
+ case ZEND_CATCH:
+ if (!(opline->extended_value & ZEND_LAST_CATCH)) {
opline->op2.jmp_addr = &op_array->opcodes[opline->op2.jmp_addr - old_opcodes];
- break;
- case ZEND_CATCH:
- if (!(opline->extended_value & ZEND_LAST_CATCH)) {
- opline->op2.jmp_addr = &op_array->opcodes[opline->op2.jmp_addr - old_opcodes];
+ }
+ break;
+ case ZEND_FE_FETCH_R:
+ case ZEND_FE_FETCH_RW:
+ case ZEND_SWITCH_LONG:
+ case ZEND_SWITCH_STRING:
+ /* relative extended_value don't have to be changed */
+ break;
+#endif
+ case ZEND_IS_IDENTICAL:
+ case ZEND_IS_NOT_IDENTICAL:
+ case ZEND_IS_EQUAL:
+ case ZEND_IS_NOT_EQUAL:
+ case ZEND_IS_SMALLER:
+ case ZEND_IS_SMALLER_OR_EQUAL:
+ case ZEND_CASE:
+ case ZEND_ISSET_ISEMPTY_CV:
+ case ZEND_ISSET_ISEMPTY_VAR:
+ case ZEND_ISSET_ISEMPTY_DIM_OBJ:
+ case ZEND_ISSET_ISEMPTY_PROP_OBJ:
+ case ZEND_ISSET_ISEMPTY_STATIC_PROP:
+ case ZEND_INSTANCEOF:
+ case ZEND_TYPE_CHECK:
+ case ZEND_DEFINED:
+ case ZEND_IN_ARRAY:
+ case ZEND_ARRAY_KEY_EXISTS:
+ if (opline->result_type & IS_TMP_VAR) {
+ /* reinitialize result_type of smart branch instructions */
+ if (opline + 1 < end) {
+ if ((opline+1)->opcode == ZEND_JMPZ
+ && (opline+1)->op1_type == IS_TMP_VAR
+ && (opline+1)->op1.var == opline->result.var) {
+ opline->result_type = IS_SMART_BRANCH_JMPZ | IS_TMP_VAR;
+ } else if ((opline+1)->opcode == ZEND_JMPNZ
+ && (opline+1)->op1_type == IS_TMP_VAR
+ && (opline+1)->op1.var == opline->result.var) {
+ opline->result_type = IS_SMART_BRANCH_JMPNZ | IS_TMP_VAR;
+ }
}
- break;
- case ZEND_FE_FETCH_R:
- case ZEND_FE_FETCH_RW:
- case ZEND_SWITCH_LONG:
- case ZEND_SWITCH_STRING:
- /* relative extended_value don't have to be changed */
- break;
- }
+ }
+ break;
}
-#endif
+ zend_vm_set_opcode_handler_ex(opline, op1_info, op2_info, res_info);
opline++;
}
+
+ op_array->fn_flags |= ZEND_ACC_DONE_PASS_TWO;
}
-#endif
static void zend_optimize_op_array(zend_op_array *op_array,
zend_optimizer_ctx *ctx)
@@ -1258,12 +1304,6 @@ static void zend_optimize_op_array(zend_op_array *op_array,
zend_redo_pass_two(op_array);
if (op_array->live_range) {
-#if HAVE_DFA_PASS
- if ((ZEND_OPTIMIZER_PASS_6 & ctx->optimization_level) &&
- (ZEND_OPTIMIZER_PASS_7 & ctx->optimization_level)) {
- return;
- }
-#endif
zend_recalc_live_ranges(op_array, NULL);
}
}
@@ -1288,7 +1328,6 @@ static void zend_adjust_fcall_stack_size(zend_op_array *op_array, zend_optimizer
}
}
-#if HAVE_DFA_PASS
static void zend_adjust_fcall_stack_size_graph(zend_op_array *op_array)
{
zend_func_info *func_info = ZEND_FUNC_INFO(op_array);
@@ -1316,7 +1355,6 @@ static zend_bool needs_live_range(zend_op_array *op_array, zend_op *def_opline)
}
return 1;
}
-#endif
int zend_optimize_script(zend_script *script, zend_long optimization_level, zend_long debug_level)
{
@@ -1325,9 +1363,7 @@ int zend_optimize_script(zend_script *script, zend_long optimization_level, zend
zend_op_array *op_array;
zend_string *name;
zend_optimizer_ctx ctx;
-#if HAVE_DFA_PASS
zend_call_graph call_graph;
-#endif
ctx.arena = zend_arena_create(64 * 1024);
ctx.script = script;
@@ -1335,38 +1371,20 @@ int zend_optimize_script(zend_script *script, zend_long optimization_level, zend
ctx.optimization_level = optimization_level;
ctx.debug_level = debug_level;
- zend_optimize_op_array(&script->main_op_array, &ctx);
-
- ZEND_HASH_FOREACH_PTR(&script->function_table, op_array) {
- zend_optimize_op_array(op_array, &ctx);
- } ZEND_HASH_FOREACH_END();
-
- ZEND_HASH_FOREACH_STR_KEY_PTR(&script->class_table, key, ce) {
- if (ce->refcount > 1 && !zend_string_equals_ci(key, ce->name)) {
- continue;
- }
- ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->function_table, name, op_array) {
- if (op_array->scope == ce
- && op_array->type == ZEND_USER_FUNCTION
- && !(op_array->fn_flags & ZEND_ACC_TRAIT_CLONE)) {
- zend_optimize_op_array(op_array, &ctx);
- }
- } ZEND_HASH_FOREACH_END();
- } ZEND_HASH_FOREACH_END();
-
-#if HAVE_DFA_PASS
if ((ZEND_OPTIMIZER_PASS_6 & optimization_level) &&
(ZEND_OPTIMIZER_PASS_7 & optimization_level) &&
- zend_build_call_graph(&ctx.arena, script, ZEND_RT_CONSTANTS, &call_graph) == SUCCESS) {
+ zend_build_call_graph(&ctx.arena, script, &call_graph) == SUCCESS) {
/* Optimize using call-graph */
- void *checkpoint = zend_arena_checkpoint(ctx.arena);
int i;
zend_func_info *func_info;
for (i = 0; i < call_graph.op_arrays_count; i++) {
zend_revert_pass_two(call_graph.op_arrays[i]);
+ zend_optimize(call_graph.op_arrays[i], &ctx);
}
+ zend_analyze_call_graph(&ctx.arena, script, &call_graph);
+
for (i = 0; i < call_graph.op_arrays_count; i++) {
func_info = ZEND_FUNC_INFO(call_graph.op_arrays[i]);
if (func_info) {
@@ -1445,16 +1463,11 @@ int zend_optimize_script(zend_script *script, zend_long optimization_level, zend
for (i = 0; i < call_graph.op_arrays_count; i++) {
ZEND_SET_FUNC_INFO(call_graph.op_arrays[i], NULL);
}
-
- zend_arena_release(&ctx.arena, checkpoint);
- } else
-#endif
-
- if (ZEND_OPTIMIZER_PASS_12 & optimization_level) {
- zend_adjust_fcall_stack_size(&script->main_op_array, &ctx);
+ } else {
+ zend_optimize_op_array(&script->main_op_array, &ctx);
ZEND_HASH_FOREACH_PTR(&script->function_table, op_array) {
- zend_adjust_fcall_stack_size(op_array, &ctx);
+ zend_optimize_op_array(op_array, &ctx);
} ZEND_HASH_FOREACH_END();
ZEND_HASH_FOREACH_STR_KEY_PTR(&script->class_table, key, ce) {
@@ -1465,10 +1478,31 @@ int zend_optimize_script(zend_script *script, zend_long optimization_level, zend
if (op_array->scope == ce
&& op_array->type == ZEND_USER_FUNCTION
&& !(op_array->fn_flags & ZEND_ACC_TRAIT_CLONE)) {
- zend_adjust_fcall_stack_size(op_array, &ctx);
+ zend_optimize_op_array(op_array, &ctx);
}
} ZEND_HASH_FOREACH_END();
} ZEND_HASH_FOREACH_END();
+
+ if (ZEND_OPTIMIZER_PASS_12 & optimization_level) {
+ zend_adjust_fcall_stack_size(&script->main_op_array, &ctx);
+
+ ZEND_HASH_FOREACH_PTR(&script->function_table, op_array) {
+ zend_adjust_fcall_stack_size(op_array, &ctx);
+ } ZEND_HASH_FOREACH_END();
+
+ ZEND_HASH_FOREACH_STR_KEY_PTR(&script->class_table, key, ce) {
+ if (ce->refcount > 1 && !zend_string_equals_ci(key, ce->name)) {
+ continue;
+ }
+ ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->function_table, name, op_array) {
+ if (op_array->scope == ce
+ && op_array->type == ZEND_USER_FUNCTION
+ && !(op_array->fn_flags & ZEND_ACC_TRAIT_CLONE)) {
+ zend_adjust_fcall_stack_size(op_array, &ctx);
+ }
+ } ZEND_HASH_FOREACH_END();
+ } ZEND_HASH_FOREACH_END();
+ }
}
ZEND_HASH_FOREACH_STR_KEY_PTR(&script->class_table, key, ce) {
@@ -1498,11 +1532,11 @@ int zend_optimize_script(zend_script *script, zend_long optimization_level, zend
if ((debug_level & ZEND_DUMP_AFTER_OPTIMIZER) &&
(ZEND_OPTIMIZER_PASS_7 & optimization_level)) {
zend_dump_op_array(&script->main_op_array,
- ZEND_DUMP_RT_CONSTANTS | ZEND_DUMP_LIVE_RANGES, "after optimizer", NULL);
+ ZEND_DUMP_LIVE_RANGES, "after optimizer", NULL);
ZEND_HASH_FOREACH_PTR(&script->function_table, op_array) {
zend_dump_op_array(op_array,
- ZEND_DUMP_RT_CONSTANTS | ZEND_DUMP_LIVE_RANGES, "after optimizer", NULL);
+ ZEND_DUMP_LIVE_RANGES, "after optimizer", NULL);
} ZEND_HASH_FOREACH_END();
ZEND_HASH_FOREACH_PTR(&script->class_table, ce) {
@@ -1511,7 +1545,7 @@ int zend_optimize_script(zend_script *script, zend_long optimization_level, zend
&& op_array->type == ZEND_USER_FUNCTION
&& !(op_array->fn_flags & ZEND_ACC_TRAIT_CLONE)) {
zend_dump_op_array(op_array,
- ZEND_DUMP_RT_CONSTANTS | ZEND_DUMP_LIVE_RANGES, "after optimizer", NULL);
+ ZEND_DUMP_LIVE_RANGES, "after optimizer", NULL);
}
} ZEND_HASH_FOREACH_END();
} ZEND_HASH_FOREACH_END();
diff --git a/ext/opcache/Optimizer/zend_optimizer.h b/ext/opcache/Optimizer/zend_optimizer.h
index 2841d018a5..04528d33e2 100644
--- a/ext/opcache/Optimizer/zend_optimizer.h
+++ b/ext/opcache/Optimizer/zend_optimizer.h
@@ -25,9 +25,9 @@
#include "zend.h"
#include "zend_compile.h"
-#define ZEND_OPTIMIZER_PASS_1 (1<<0) /* CSE, STRING construction */
-#define ZEND_OPTIMIZER_PASS_2 (1<<1) /* Constant conversion and jumps */
-#define ZEND_OPTIMIZER_PASS_3 (1<<2) /* ++, +=, series of jumps */
+#define ZEND_OPTIMIZER_PASS_1 (1<<0) /* Simple local optimizations */
+#define ZEND_OPTIMIZER_PASS_2 (1<<1) /* */
+#define ZEND_OPTIMIZER_PASS_3 (1<<2) /* Jump optimization */
#define ZEND_OPTIMIZER_PASS_4 (1<<3) /* INIT_FCALL_BY_NAME -> DO_FCALL */
#define ZEND_OPTIMIZER_PASS_5 (1<<4) /* CFG based optimization */
#define ZEND_OPTIMIZER_PASS_6 (1<<5) /* DFA based optimization */
diff --git a/ext/opcache/Optimizer/zend_optimizer_internal.h b/ext/opcache/Optimizer/zend_optimizer_internal.h
index 9ab18f6398..43ac1ea07f 100644
--- a/ext/opcache/Optimizer/zend_optimizer_internal.h
+++ b/ext/opcache/Optimizer/zend_optimizer_internal.h
@@ -93,7 +93,6 @@ int zend_optimizer_replace_by_const(zend_op_array *op_array,
zend_op *zend_optimizer_get_loop_var_def(const zend_op_array *op_array, zend_op *free_opline);
void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx);
-void zend_optimizer_pass2(zend_op_array *op_array);
void zend_optimizer_pass3(zend_op_array *op_array, zend_optimizer_ctx *ctx);
void zend_optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx);
void zend_optimize_cfg(zend_op_array *op_array, zend_optimizer_ctx *ctx);
@@ -106,7 +105,7 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
void zend_optimizer_compact_vars(zend_op_array *op_array);
int zend_optimizer_is_disabled_func(const char *name, size_t len);
zend_function *zend_optimizer_get_called_func(
- zend_script *script, zend_op_array *op_array, zend_op *opline, zend_bool rt_constants);
+ zend_script *script, zend_op_array *op_array, zend_op *opline);
uint32_t zend_optimizer_classify_function(zend_string *name, uint32_t num_args);
void zend_optimizer_migrate_jump(zend_op_array *op_array, zend_op *new_opline, zend_op *opline);
void zend_optimizer_shift_jump(zend_op_array *op_array, zend_op *opline, uint32_t *shiftlist);
diff --git a/ext/opcache/Optimizer/zend_ssa.c b/ext/opcache/Optimizer/zend_ssa.c
index 9d3b81ca83..99d577dd2c 100644
--- a/ext/opcache/Optimizer/zend_ssa.c
+++ b/ext/opcache/Optimizer/zend_ssa.c
@@ -192,14 +192,14 @@ static int find_adjusted_tmp_var(const zend_op_array *op_array, uint32_t build_f
}
} else if (op->opcode == ZEND_ADD) {
if (op->op1_type == IS_CV && op->op2_type == IS_CONST) {
- zv = CRT_CONSTANT_EX(op_array, op, op->op2, (build_flags & ZEND_RT_CONSTANTS));
+ zv = CRT_CONSTANT_EX(op_array, op, op->op2);
if (Z_TYPE_P(zv) == IS_LONG
&& Z_LVAL_P(zv) != ZEND_LONG_MIN) {
*adjustment = -Z_LVAL_P(zv);
return EX_VAR_TO_NUM(op->op1.var);
}
} else if (op->op2_type == IS_CV && op->op1_type == IS_CONST) {
- zv = CRT_CONSTANT_EX(op_array, op, op->op1, (build_flags & ZEND_RT_CONSTANTS));
+ zv = CRT_CONSTANT_EX(op_array, op, op->op1);
if (Z_TYPE_P(zv) == IS_LONG
&& Z_LVAL_P(zv) != ZEND_LONG_MIN) {
*adjustment = -Z_LVAL_P(zv);
@@ -208,7 +208,7 @@ static int find_adjusted_tmp_var(const zend_op_array *op_array, uint32_t build_f
}
} else if (op->opcode == ZEND_SUB) {
if (op->op1_type == IS_CV && op->op2_type == IS_CONST) {
- zv = CRT_CONSTANT_EX(op_array, op, op->op2, (build_flags & ZEND_RT_CONSTANTS));
+ zv = CRT_CONSTANT_EX(op_array, op, op->op2);
if (Z_TYPE_P(zv) == IS_LONG) {
*adjustment = Z_LVAL_P(zv);
return EX_VAR_TO_NUM(op->op1.var);
@@ -293,7 +293,7 @@ static void place_essa_pis(
} else if (var1 >= 0 && var2 < 0) {
zend_long add_val2 = 0;
if ((opline-1)->op2_type == IS_CONST) {
- zval *zv = CRT_CONSTANT_EX(op_array, (opline-1), (opline-1)->op2, (build_flags & ZEND_RT_CONSTANTS));
+ zval *zv = CRT_CONSTANT_EX(op_array, (opline-1), (opline-1)->op2);
if (Z_TYPE_P(zv) == IS_LONG) {
add_val2 = Z_LVAL_P(zv);
@@ -315,9 +315,9 @@ static void place_essa_pis(
} else if (var1 < 0 && var2 >= 0) {
zend_long add_val1 = 0;
if ((opline-1)->op1_type == IS_CONST) {
- zval *zv = CRT_CONSTANT_EX(op_array, (opline-1), (opline-1)->op1, (build_flags & ZEND_RT_CONSTANTS));
+ zval *zv = CRT_CONSTANT_EX(op_array, (opline-1), (opline-1)->op1);
if (Z_TYPE_P(zv) == IS_LONG) {
- add_val1 = Z_LVAL_P(CRT_CONSTANT_EX(op_array, (opline-1), (opline-1)->op1, (build_flags & ZEND_RT_CONSTANTS)));
+ add_val1 = Z_LVAL_P(CRT_CONSTANT_EX(op_array, (opline-1), (opline-1)->op1));
} else if (Z_TYPE_P(zv) == IS_FALSE) {
add_val1 = 0;
} else if (Z_TYPE_P(zv) == IS_TRUE) {
@@ -463,10 +463,10 @@ static void place_essa_pis(
uint32_t type_mask;
if ((opline-1)->op1_type == IS_CV && (opline-1)->op2_type == IS_CONST) {
var = EX_VAR_TO_NUM((opline-1)->op1.var);
- val = CRT_CONSTANT_EX(op_array, (opline-1), (opline-1)->op2, (build_flags & ZEND_RT_CONSTANTS));
+ val = CRT_CONSTANT_EX(op_array, (opline-1), (opline-1)->op2);
} else if ((opline-1)->op1_type == IS_CONST && (opline-1)->op2_type == IS_CV) {
var = EX_VAR_TO_NUM((opline-1)->op2.var);
- val = CRT_CONSTANT_EX(op_array, (opline-1), (opline-1)->op1, (build_flags & ZEND_RT_CONSTANTS));
+ val = CRT_CONSTANT_EX(op_array, (opline-1), (opline-1)->op1);
} else {
continue;
}
@@ -497,7 +497,7 @@ static void place_essa_pis(
opline->op1.var == (opline-1)->result.var && (opline-1)->op1_type == IS_CV &&
(opline-1)->op2_type == IS_CONST) {
int var = EX_VAR_TO_NUM((opline-1)->op1.var);
- zend_string *lcname = Z_STR_P(CRT_CONSTANT_EX(op_array, (opline-1), (opline-1)->op2, (build_flags & ZEND_RT_CONSTANTS)) + 1);
+ zend_string *lcname = Z_STR_P(CRT_CONSTANT_EX(op_array, (opline-1), (opline-1)->op2) + 1);
zend_class_entry *ce = script ? zend_hash_find_ptr(&script->class_table, lcname) : NULL;
if (!ce) {
ce = zend_hash_find_ptr(CG(class_table), lcname);
@@ -742,10 +742,6 @@ static int zend_ssa_rename(const zend_op_array *op_array, uint32_t build_flags,
case ZEND_FETCH_DIM_RW:
case ZEND_FETCH_DIM_FUNC_ARG:
case ZEND_FETCH_DIM_UNSET:
- case ZEND_FETCH_OBJ_W:
- case ZEND_FETCH_OBJ_RW:
- case ZEND_FETCH_OBJ_FUNC_ARG:
- case ZEND_FETCH_OBJ_UNSET:
case ZEND_FETCH_LIST_W:
if (opline->op1_type == IS_CV) {
ssa_ops[k].op1_def = ssa_vars_count;
@@ -885,7 +881,6 @@ int zend_build_ssa(zend_arena **arena, const zend_script *script, const zend_op_
return FAILURE;
}
- ssa->rt_constants = (build_flags & ZEND_RT_CONSTANTS);
ssa_blocks = zend_arena_calloc(arena, blocks_count, sizeof(zend_ssa_block));
ssa->blocks = ssa_blocks;
@@ -1125,8 +1120,6 @@ int zend_ssa_compute_use_def_chains(zend_arena **arena, const zend_op_array *op_
for (i = 0; i < op_array->last_var; i++) {
if ((ssa->cfg.flags & ZEND_FUNC_INDIRECT_VAR_ACCESS)) {
ssa_vars[i].alias = SYMTABLE_ALIAS;
- } else if (zend_string_equals_literal(op_array->vars[i], "php_errormsg")) {
- ssa_vars[i].alias = PHP_ERRORMSG_ALIAS;
} else if (zend_string_equals_literal(op_array->vars[i], "http_response_header")) {
ssa_vars[i].alias = HTTP_RESPONSE_HEADER_ALIAS;
}
diff --git a/ext/opcache/Optimizer/zend_ssa.h b/ext/opcache/Optimizer/zend_ssa.h
index a921a5bbe0..1987a47fc4 100644
--- a/ext/opcache/Optimizer/zend_ssa.h
+++ b/ext/opcache/Optimizer/zend_ssa.h
@@ -95,7 +95,6 @@ typedef struct _zend_ssa_op {
typedef enum _zend_ssa_alias_kind {
NO_ALIAS,
SYMTABLE_ALIAS,
- PHP_ERRORMSG_ALIAS,
HTTP_RESPONSE_HEADER_ALIAS
} zend_ssa_alias_kind;
@@ -132,12 +131,11 @@ typedef struct _zend_ssa_var_info {
typedef struct _zend_ssa {
zend_cfg cfg; /* control flow graph */
- int rt_constants; /* run-time or compile-time */
int vars_count; /* number of SSA variables */
+ int sccs; /* number of SCCs */
zend_ssa_block *blocks; /* array of SSA blocks */
zend_ssa_op *ops; /* array of SSA instructions */
zend_ssa_var *vars; /* use/def chain of SSA variables */
- int sccs; /* number of SCCs */
zend_ssa_var_info *var_info;
} zend_ssa;