86#define TOP ((uint8_t)-1)
87#define BOT ((uint8_t)-2)
88#define PARTIAL_ARRAY ((uint8_t)-3)
89#define PARTIAL_OBJECT ((uint8_t)-4)
90#define IS_TOP(zv) (Z_TYPE_P(zv) == TOP)
91#define IS_BOT(zv) (Z_TYPE_P(zv) == BOT)
92#define IS_PARTIAL_ARRAY(zv) (Z_TYPE_P(zv) == PARTIAL_ARRAY)
93#define IS_PARTIAL_OBJECT(zv) (Z_TYPE_P(zv) == PARTIAL_OBJECT)
95#define MAKE_PARTIAL_ARRAY(zv) (Z_TYPE_INFO_P(zv) = PARTIAL_ARRAY | (IS_TYPE_REFCOUNTED << Z_TYPE_FLAGS_SHIFT))
96#define MAKE_PARTIAL_OBJECT(zv) (Z_TYPE_INFO_P(zv) = PARTIAL_OBJECT | (IS_TYPE_REFCOUNTED << Z_TYPE_FLAGS_SHIFT))
98#define MAKE_TOP(zv) (Z_TYPE_INFO_P(zv) = TOP)
99#define MAKE_BOT(zv) (Z_TYPE_INFO_P(zv) = BOT)
101static void scp_dump_value(
zval *
zv) {
119static void empty_partial_array(
zval *
zv)
125static void dup_partial_array(
zval *dst,
const zval *src)
131static void empty_partial_object(
zval *
zv)
137static void dup_partial_object(
zval *dst,
const zval *src)
143static inline bool value_known(
zval *
zv) {
156 fprintf(stderr,
"Lowering #%d.", var);
159 scp_dump_value(
value);
166 zval_ptr_dtor_nogc(
value);
168 scdf_add_to_worklist(scdf, var);
176 zval_ptr_dtor_nogc(
value);
178 scdf_add_to_worklist(scdf, var);
192 }
else if (ssa_op->
op1_use != -1) {
202 }
else if (ssa_op->
op2_use != -1) {
209static bool can_replace_op1(
279static bool can_replace_op2(
292static bool try_replace_op1(
300 zval_ptr_dtor_nogc(&
zv);
305static bool try_replace_op2(
313 zval_ptr_dtor_nogc(&
zv);
329 if (zend_hash_num_elements(
Z_ARRVAL_P(op)) == 0) {
349 if (
IS_LONG == is_numeric_string(
375 if (!zend_is_long_compatible(
Z_DVAL_P(
op2), lval)) {
398 if (zval_to_string_offset(&index,
op2) ==
FAILURE) {
435 return ct_eval_isset_isempty(
result, extended_value,
value);
463 if (!zend_is_long_compatible(
Z_DVAL_P(
key), lval)) {
508 if (!zend_is_long_compatible(
Z_DVAL_P(
key), lval)) {
565 || zval_to_string_offset(&index,
key) ==
FAILURE || index < 0) {
570 new_str = zend_string_alloc(index + 1, 0);
578 value_str = zval_get_string(
value);
619 return ct_eval_isset_isempty(
result, extended_value,
value);
657 empty_partial_object(
result);
693static inline void ct_eval_type_check(
zval *
result, uint32_t type_mask,
zval *
op1) {
713 }
else if (extended_value) {
813 dummy_frame.
opline = &dummy_opline;
823 EG(capture_warnings_during_sccp) = 1;
843 if (
EG(capture_warnings_during_sccp) > 1) {
847 EG(capture_warnings_during_sccp) = 0;
863#define SET_RESULT(op, zv) do { \
864 if (ssa_op->op##_def >= 0) { \
865 set_value(scdf, ctx, ssa_op->op##_def, zv); \
868#define SET_RESULT_BOT(op) SET_RESULT(op, &ctx->bot)
869#define SET_RESULT_TOP(op) SET_RESULT(op, &ctx->top)
871#define SKIP_IF_TOP(op) if (IS_TOP(op)) return;
877 op1 = get_op1_value(ctx, opline, ssa_op);
878 op2 = get_op2_value(ctx, opline, ssa_op);
895 zval *
data = get_op1_value(ctx, opline+1, ssa_op+1);
899 op1 = &
EG(uninitialized_zval);
918 empty_partial_array(&
zv);
920 zval_ptr_dtor_nogc(&
zv);
937 empty_partial_array(&
zv);
939 dup_partial_array(&
zv,
op1);
945 }
else if (ct_eval_del_array_elem(&
zv,
op2) ==
SUCCESS) {
951 zval_ptr_dtor_nogc(&
zv);
959 dup_partial_array(&
zv,
op1);
980 zval_ptr_dtor_nogc(&
zv);
988 zval *
data = get_op1_value(ctx, opline+1, ssa_op+1);
1014 empty_partial_object(&
zv);
1016 zval_ptr_dtor_nogc(&
zv);
1027 empty_partial_object(&
zv);
1029 dup_partial_object(&
zv,
op1);
1037 zval_ptr_dtor_nogc(&
zv);
1045 dup_partial_object(&
zv,
op1);
1058 zval_ptr_dtor_nogc(&
zv);
1082 opline =
call->caller_call_opline;
1121 empty_partial_array(&
zv);
1123 zval_ptr_dtor_nogc(&
zv);
1136 empty_partial_array(&
zv);
1145 }
else if (ct_eval_del_array_elem(&
zv,
op2) ==
SUCCESS) {
1150 zval_ptr_dtor_nogc(&
zv);
1181 zval_ptr_dtor_nogc(&
zv);
1207 zval_ptr_dtor_nogc(&
zv);
1213 empty_partial_object(&
zv);
1215 zval_ptr_dtor_nogc(&
zv);
1242 switch (opline->
opcode) {
1270 zval_ptr_dtor_nogc(&
zv);
1289 zval_ptr_dtor_nogc(&
zv);
1296 zval *
data = get_op1_value(ctx, opline+1, ssa_op+1);
1302 dup_partial_array(&
zv,
op1);
1303 ct_eval_del_array_elem(&
zv,
op2);
1306 zval_ptr_dtor_nogc(&tmp);
1307 zval_ptr_dtor_nogc(&
zv);
1314 zval_ptr_dtor_nogc(&tmp);
1319 dup_partial_array(&
zv,
op1);
1327 zval_ptr_dtor_nogc(&tmp);
1328 zval_ptr_dtor_nogc(&
zv);
1332 zval_ptr_dtor_nogc(&tmp);
1333 zval_ptr_dtor_nogc(&
zv);
1341 zval *
data = get_op1_value(ctx, opline+1, ssa_op+1);
1347 dup_partial_object(&
zv,
op1);
1348 ct_eval_del_obj_prop(&
zv,
op2);
1351 zval_ptr_dtor_nogc(&tmp);
1352 zval_ptr_dtor_nogc(&
zv);
1359 zval_ptr_dtor_nogc(&tmp);
1363 dup_partial_object(&
zv,
op1);
1368 zval_ptr_dtor_nogc(&tmp);
1369 zval_ptr_dtor_nogc(&
zv);
1373 zval_ptr_dtor_nogc(&tmp);
1374 zval_ptr_dtor_nogc(&
zv);
1395 dup_partial_object(&
zv,
op1);
1396 ct_eval_assign_obj(&
zv, &tmp2,
op2);
1402 zval_ptr_dtor_nogc(&
tmp1);
1403 zval_ptr_dtor_nogc(&tmp2);
1405 zval_ptr_dtor_nogc(&
zv);
1408 zval_ptr_dtor_nogc(&
tmp1);
1421 zval_ptr_dtor_nogc(&
zv);
1433 zval_ptr_dtor_nogc(&
zv);
1447 zval_ptr_dtor_nogc(&
zv);
1460 zval_ptr_dtor_nogc(&
zv);
1471 zval_ptr_dtor_nogc(&
zv);
1480 zval_ptr_dtor_nogc(&
zv);
1500 zval_ptr_dtor_nogc(&
zv);
1510 zval_ptr_dtor_nogc(&
zv);
1520 zval_ptr_dtor_nogc(&
zv);
1533 zval_ptr_dtor_nogc(&
zv);
1544 zval_ptr_dtor_nogc(&
zv);
1557 zval_ptr_dtor_nogc(&
zv);
1570 zval_ptr_dtor_nogc(&
zv);
1604 zval_ptr_dtor_nogc(&
zv);
1613 zval_ptr_dtor_nogc(&
zv);
1628 zval_ptr_dtor_nogc(&
zv);
1642 zval_ptr_dtor_nogc(&
zv);
1668 if (
call->num_args > 3 ||
call->send_unpack ||
call->is_prototype ||
call->named_args) {
1673 for (i = 0; i <
call->num_args; i++) {
1680 args[i] = get_op1_value(ctx, opline,
1699 zval_ptr_dtor_nogc(&
zv);
1731 zend_op *op_data = opline + 1;
1742 for (uint32_t i = 0; i <
num_args; i++) {
1755 zval_ptr_dtor_nogc(&
zv);
1772static zval *value_from_type_and_range(
sccp_ctx *ctx,
int var_num,
zval *tmp) {
1824static void sccp_mark_feasible_successors(
1833 switch (opline->
opcode) {
1844 op1 = get_op1_value(ctx, opline, ssa_op);
1847 op1 = value_from_type_and_range(ctx, ssa_op->
op1_use, &
zv);
1852 for (
s = 0;
s < block->successors_count;
s++) {
1863 switch (opline->
opcode) {
1932 }
else if (strict_comparison) {
1939 s = block->successors_count - 1;
1943 for (
s = 0;
s < block->successors_count;
s++) {
1983 empty_partial_array(&
ret);
1985 zval_ptr_dtor_nogc(
a);
1999 empty_partial_object(&
ret);
2001 zval_ptr_dtor_nogc(
a);
2007static void join_phi_values(
zval *
a,
zval *b,
bool escape) {
2012 zval_ptr_dtor_nogc(
a);
2017 zval_ptr_dtor_nogc(
a);
2022 if (join_partial_arrays(
a, b) ==
FAILURE) {
2023 zval_ptr_dtor_nogc(
a);
2027 if (escape || join_partial_objects(
a, b) ==
FAILURE) {
2028 zval_ptr_dtor_nogc(
a);
2032 if (join_partial_arrays(
a, b) ==
FAILURE) {
2033 zval_ptr_dtor_nogc(
a);
2045 int *predecessors = &ssa->
cfg.
predecessors[block->predecessor_offset];
2051 fprintf(stderr,
"Handling phi(");
2055 if (scdf_is_edge_feasible(scdf, phi->
pi, phi->
block)) {
2059 for (i = 0; i < block->predecessors_count; i++) {
2061 if (scdf_is_edge_feasible(scdf, predecessors[i], phi->
block)) {
2079 zval_ptr_dtor_nogc(&
result);
2099 for (i = 0; i <
call->num_args; i++) {
2107 return call->num_args + 2;
2127 int removed_ops = 0;
2138 zend_ssa_remove_result_def(ssa, ssa_op);
2144 switch (opline->
opcode) {
2169 zend_ssa_remove_result_def(ssa, ssa_op);
2206 removed_ops = remove_call(ctx, opline, ssa_op) - 1;
2235 zend_ssa_remove_result_def(ssa, ssa_op);
2246 zend_ssa_remove_result_def(ssa, ssa_op);
2248 removed_ops = remove_call(ctx, opline, ssa_op);
2259 }
else if (ssa_op->
op1_def == var_num) {
2269 switch (opline->
opcode) {
2277 || ((ssa_op+1)->op1_use >= 0 &&!value_known(&ctx->
values[(ssa_op+1)->op1_use]))) {
2307 zend_ssa_remove_result_def(ssa, ssa_op);
2319 }
else if (ssa_op->
op2_use >= 0) {
2328 switch (opline->
opcode) {
2356 zend_ssa_remove_op1_def(ssa, ssa_op);
2371static int replace_constant_operands(
sccp_ctx *ctx) {
2376 int removed_ops = 0;
2392 removed_ops += try_remove_definition(ctx, i, var,
NULL);
2395 }
else if (value_known(&ctx->
values[i])) {
2398 value = value_from_type_and_range(ctx, i, &tmp);
2407 if (try_replace_op1(ctx, opline, ssa_op, i,
value)) {
2420 if (try_replace_op2(ctx, opline, ssa_op, i,
value)) {
2430 if (value_known(&ctx->
values[i])) {
2431 removed_ops += try_remove_definition(ctx, i, var,
value);
2448 for (; i < op_array->
last_var; ++i) {
2462static void sccp_context_free(
sccp_ctx *sccp) {
2465 zval_ptr_dtor_nogc(&sccp->
values[i]);
2472 int removed_ops = 0;
2473 void *checkpoint = zend_arena_checkpoint(ctx->
arena);
2475 sccp_context_init(ctx, &sccp, ssa, op_array, call_map);
2487 for (i = op_array->
last_var; i < ssa->vars_count; i++) {
2495 fprintf(stderr,
"\nSCCP Values for \"");
2508 removed_ops += replace_constant_operands(&sccp);
2510 sccp_context_free(&sccp);
2511 zend_arena_release(&ctx->
arena, checkpoint);
fprintf($stream, string $format, mixed ... $values)
memset(ptr, 0, type->size)
unsigned char key[REFLECTION_KEY_LEN]
#define SET_RESULT(op, zv)
int sccp_optimize_op_array(zend_optimizer_ctx *ctx, zend_op_array *op_array, zend_ssa *ssa, zend_call_info **call_map)
#define SET_RESULT_BOT(op)
#define IS_PARTIAL_ARRAY(zv)
#define MAKE_PARTIAL_ARRAY(zv)
#define IS_PARTIAL_OBJECT(zv)
struct _sccp_ctx sccp_ctx
#define MAKE_PARTIAL_OBJECT(zv)
void scdf_init(zend_optimizer_ctx *ctx, scdf_ctx *scdf, zend_op_array *op_array, zend_ssa *ssa)
void scdf_solve(scdf_ctx *scdf, const char *name)
uint32_t scdf_remove_unreachable_blocks(scdf_ctx *scdf)
void scdf_mark_edge_feasible(scdf_ctx *scdf, int from, int to)
struct _scdf_ctx scdf_ctx
zend_call_info ** call_map
void(* visit_phi)(struct _scdf_ctx *scdf, zend_ssa_phi *phi)
void(* mark_feasible_successors)(struct _scdf_ctx *scdf, int block_num, zend_basic_block *block, zend_op *opline, zend_ssa_op *ssa_op)
void(* visit_instr)(struct _scdf_ctx *scdf, zend_op *opline, zend_ssa_op *ssa_op)
struct _scdf_ctx::@015351274142365124137142230002251013147010033176 handlers
zend_basic_block * blocks
unsigned int escape_state
zend_ssa_phi * definition_phi
zend_ssa_phi * phi_use_chain
zend_ssa_var_info * var_info
#define safe_emalloc(nmemb, size, offset)
struct _zend_basic_block zend_basic_block
zend_string_release_ex(func->internal_function.function_name, 0)
#define ZEND_SHORT_CIRCUITING_CHAIN_EXPR
#define ZEND_ACC_HAS_TYPE_HINTS
#define ZEND_ACC_COMPILE_TIME_EVAL
#define ZEND_INTERNAL_FUNCTION
#define ZEND_OFFSET_TO_OPLINE_NUM(op_array, base, offset)
#define ZEND_CALL_FRAME_SLOT
#define ZEND_SHORT_CIRCUITING_CHAIN_EMPTY
struct _zend_op_array zend_op_array
#define ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES
#define ZEND_ARRAY_ELEMENT_REF
#define CT_CONSTANT_EX(op_array, num)
#define ZEND_ACC_RETURN_REFERENCE
#define ZEND_SHORT_CIRCUITING_CHAIN_MASK
#define ZEND_SHORT_CIRCUITING_CHAIN_ISSET
void zend_dump_op_array_name(const zend_op_array *op_array)
void zend_dump_const(const zval *zv)
ZEND_API void zend_dump_var(const zend_op_array *op_array, uint8_t var_type, uint32_t var_num)
void zend_dump_ht(HashTable *ht)
ZEND_API void zend_clear_exception(void)
union _zend_function zend_function
#define ZEND_FLF_NUM_ARGS(opcode)
#define ZEND_FLF_FUNC(opline)
struct _zend_call_info zend_call_info
ZEND_API zval *ZEND_FASTCALL zend_hash_next_index_insert(HashTable *ht, zval *pData)
ZEND_API zval *ZEND_FASTCALL zend_hash_index_add_new(HashTable *ht, zend_ulong h, zval *pData)
ZEND_API zval *ZEND_FASTCALL zend_hash_add_new(HashTable *ht, zend_string *key, zval *pData)
ZEND_API zend_result ZEND_FASTCALL zend_hash_index_del(HashTable *ht, zend_ulong h)
ZEND_API zval *ZEND_FASTCALL zend_hash_index_update(HashTable *ht, zend_ulong h, zval *pData)
ZEND_API void ZEND_FASTCALL zend_array_destroy(HashTable *ht)
ZEND_API HashTable *ZEND_FASTCALL zend_array_dup(HashTable *source)
ZEND_API zval *ZEND_FASTCALL zend_hash_update(HashTable *ht, zend_string *key, zval *pData)
ZEND_API zend_result ZEND_FASTCALL zend_hash_del(HashTable *ht, zend_string *key)
ZEND_API zval *ZEND_FASTCALL zend_hash_find(const HashTable *ht, zend_string *key)
ZEND_API zval *ZEND_FASTCALL zend_hash_index_find(const HashTable *ht, zend_ulong h)
#define zend_new_array(size)
#define ZEND_HASH_FOREACH_KEY_VAL(ht, _h, _key, _val)
#define ZEND_HASH_FOREACH_STR_KEY_VAL(ht, _key, _val)
#define ZEND_HASH_MAP_FOREACH_STR_KEY(ht, _key)
#define ZEND_HASH_FOREACH_END()
ZEND_API bool zend_may_throw(const zend_op *opline, const zend_ssa_op *ssa_op, const zend_op_array *op_array, const zend_ssa *ssa)
struct _zend_string zend_string
ZEND_API zend_result ZEND_FASTCALL decrement_function(zval *op1)
ZEND_API bool ZEND_FASTCALL zend_is_identical(const zval *op1, const zval *op2)
ZEND_API int ZEND_FASTCALL zend_compare(zval *op1, zval *op2)
ZEND_API bool ZEND_FASTCALL zend_is_true(const zval *op)
ZEND_API zend_result ZEND_FASTCALL increment_function(zval *op1)
bool zend_optimizer_update_op1_const(zend_op_array *op_array, zend_op *opline, zval *val)
zend_result zend_optimizer_eval_strlen(zval *result, const zval *op1)
int zend_optimizer_add_literal(zend_op_array *op_array, const zval *zv)
zend_result zend_optimizer_eval_binary_op(zval *result, uint8_t opcode, zval *op1, zval *op2)
zend_result zend_optimizer_eval_cast(zval *result, uint32_t type, zval *op1)
zend_result zend_optimizer_eval_special_func_call(zval *result, zend_string *name, zend_string *arg)
zend_result zend_optimizer_eval_unary_op(zval *result, uint8_t opcode, zval *op1)
bool zend_optimizer_update_op2_const(zend_op_array *op_array, zend_op *opline, zval *val)
#define ZEND_OP2_LITERAL(opline)
struct _zend_optimizer_ctx zend_optimizer_ctx
#define EXPECTED(condition)
#define ZEND_UNREACHABLE()
#define EMPTY_SWITCH_DEFAULT_CASE()
void zend_ssa_remove_instr(zend_ssa *ssa, zend_op *opline, zend_ssa_op *ssa_op)
void zend_ssa_unlink_use_chain(zend_ssa *ssa, int op, int var)
void zend_ssa_remove_phi(zend_ssa *ssa, zend_ssa_phi *phi)
void zend_ssa_rename_var_uses(zend_ssa *ssa, int old, int new, bool update_types)
#define FOREACH_USE_END()
struct _zend_ssa zend_ssa
struct _zend_ssa_var zend_ssa_var
#define FOREACH_USE(var, use)
struct _zend_ssa_phi zend_ssa_phi
struct _zend_ssa_op zend_ssa_op
struct _zend_ssa_var_info zend_ssa_var_info
#define zend_string_equals_literal(str, literal)
#define ZSTR_EMPTY_ALLOC()
#define Z_TRY_ADDREF_P(pz)
#define Z_STRVAL_P(zval_p)
#define Z_ARRVAL_P(zval_p)
struct _zend_array HashTable
#define Z_STRLEN_P(zval_p)
ZEND_RESULT_CODE zend_result
#define SEPARATE_ARRAY(zv)
struct _zend_execute_data zend_execute_data
#define ZVAL_COPY_VALUE(z, v)
ZEND_API void zval_ptr_dtor(zval *zval_ptr)
#define ZEND_IS_IDENTICAL
#define ZEND_ASSIGN_DIM_OP
#define ZEND_ASSIGN_STATIC_PROP_REF
#define ZEND_ISSET_ISEMPTY_CV
#define ZEND_VERIFY_RETURN_TYPE
#define ZEND_FETCH_LIST_R
#define ZEND_INCLUDE_OR_EVAL
#define ZEND_FRAMELESS_ICALL_0
#define ZEND_FETCH_LIST_W
#define ZEND_ASSERT_CHECK
#define ZEND_SWITCH_STRING
#define ZEND_DECLARE_CLASS_DELAYED
#define ZEND_FETCH_OBJ_FUNC_ARG
#define ZEND_ASSIGN_STATIC_PROP_OP
#define ZEND_FETCH_DIM_FUNC_ARG
#define ZEND_FRAMELESS_ICALL_1
#define ZEND_IS_NOT_EQUAL
#define ZEND_IS_NOT_IDENTICAL
#define ZEND_FETCH_OBJ_IS
#define ZEND_FETCH_OBJ_UNSET
#define ZEND_POST_DEC_OBJ
#define ZEND_ISSET_ISEMPTY_PROP_OBJ
#define ZEND_FRAMELESS_ICALL_3
#define ZEND_ADD_ARRAY_ELEMENT
#define ZEND_ASSIGN_STATIC_PROP
#define ZEND_IS_SMALLER_OR_EQUAL
#define ZEND_FRAMELESS_ICALL_2
#define ZEND_BIND_LEXICAL
#define ZEND_SEND_FUNC_ARG
#define ZEND_ISSET_ISEMPTY_DIM_OBJ
#define ZEND_BIND_INIT_STATIC_OR_JMP
#define ZEND_ADD_ARRAY_UNPACK
#define ZEND_ARRAY_KEY_EXISTS
#define ZEND_ASSIGN_OBJ_OP
#define ZEND_ASSIGN_OBJ_REF
#define ZEND_FETCH_DIM_IS
#define ZEND_FETCH_OBJ_RW
#define ZEND_FETCH_DIM_UNSET
#define ZEND_POST_INC_OBJ
#define ZEND_DO_FCALL_BY_NAME
#define ZEND_FETCH_DIM_RW