Skip to content

Implement INIT_FCALL IS_PTR specialization #13518

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Zend/Optimizer/optimize_func_calls.c
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ void zend_optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx)
fcall->opcode = ZEND_INIT_FCALL;
fcall->op1.num = zend_vm_calc_used_stack(fcall->extended_value, call_stack[call].func);
literal_dtor(&ZEND_OP2_LITERAL(fcall));
// FIXME: Use IS_PTR if possible
fcall->op2.constant = fcall->op2.constant + 1;
if (opline->opcode != ZEND_CALLABLE_CONVERT) {
opline->opcode = zend_get_call_op(fcall, call_stack[call].func);
Expand All @@ -206,6 +207,7 @@ void zend_optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx)
fcall->op1.num = zend_vm_calc_used_stack(fcall->extended_value, call_stack[call].func);
literal_dtor(&op_array->literals[fcall->op2.constant]);
literal_dtor(&op_array->literals[fcall->op2.constant + 2]);
// FIXME: Use IS_PTR if possible
fcall->op2.constant = fcall->op2.constant + 1;
if (opline->opcode != ZEND_CALLABLE_CONVERT) {
opline->opcode = zend_get_call_op(fcall, call_stack[call].func);
Expand Down
20 changes: 14 additions & 6 deletions Zend/Optimizer/sccp.c
Original file line number Diff line number Diff line change
Expand Up @@ -1647,7 +1647,8 @@ static void sccp_visit_instr(scdf_ctx *scdf, zend_op *opline, zend_ssa_op *ssa_o
case ZEND_DO_ICALL:
{
zend_call_info *call;
zval *name, *args[3] = {NULL};
zval *func_zv, *args[3] = {NULL};
zend_string *name;
int i;

if (!ctx->call_map) {
Expand All @@ -1656,7 +1657,14 @@ static void sccp_visit_instr(scdf_ctx *scdf, zend_op *opline, zend_ssa_op *ssa_o
}

call = ctx->call_map[opline - ctx->scdf.op_array->opcodes];
name = CT_CONSTANT_EX(ctx->scdf.op_array, call->caller_init_opline->op2.constant);
func_zv = CT_CONSTANT_EX(ctx->scdf.op_array, call->caller_init_opline->op2.constant);
if (Z_TYPE_P(func_zv) == IS_STRING) {
name = Z_STR_P(func_zv);
} else {
ZEND_ASSERT(Z_TYPE_P(func_zv) == IS_PTR);
zend_function *func = Z_PTR_P(func_zv);
name = func->common.function_name;
}

/* We already know it can't be evaluated, don't bother checking again */
if (ssa_op->result_def < 0 || IS_BOT(&ctx->values[ssa_op->result_def])) {
Expand Down Expand Up @@ -1694,19 +1702,19 @@ static void sccp_visit_instr(scdf_ctx *scdf, zend_op *opline, zend_ssa_op *ssa_o
break;
}

if (ct_eval_func_call(scdf->op_array, &zv, Z_STR_P(name), call->num_args, args) == SUCCESS) {
if (ct_eval_func_call(scdf->op_array, &zv, name, call->num_args, args) == SUCCESS) {
SET_RESULT(result, &zv);
zval_ptr_dtor_nogc(&zv);
break;
}

#if 0
/* sort out | uniq -c | sort -n */
fprintf(stderr, "%s\n", Z_STRVAL_P(name));
fprintf(stderr, "%s\n", name);
/*if (args[1]) {
php_printf("%s %Z %Z\n", Z_STRVAL_P(name), args[0], args[1]);
php_printf("%s %Z %Z\n", name, args[0], args[1]);
} else {
php_printf("%s %Z\n", Z_STRVAL_P(name), args[0]);
php_printf("%s %Z\n", name, args[0]);
}*/
#endif

Expand Down
13 changes: 10 additions & 3 deletions Zend/Optimizer/zend_cfg.c
Original file line number Diff line number Diff line change
Expand Up @@ -333,19 +333,26 @@ ZEND_API void zend_build_cfg(zend_arena **arena, const zend_op_array *op_array,
flags |= ZEND_FUNC_HAS_CALLS;
break;
case ZEND_INIT_FCALL:
case ZEND_INIT_NS_FCALL_BY_NAME:
case ZEND_INIT_NS_FCALL_BY_NAME: {
zv = CRT_CONSTANT(opline->op2);
if (opline->opcode == ZEND_INIT_NS_FCALL_BY_NAME) {
/* The third literal is the lowercased unqualified name */
zv += 2;
}
if ((fn = zend_hash_find_ptr(EG(function_table), Z_STR_P(zv))) != NULL) {
if (Z_TYPE_P(zv) == IS_STRING) {
fn = zend_hash_find_ptr(EG(function_table), Z_STR_P(zv));
} else {
ZEND_ASSERT(Z_TYPE_P(zv) == IS_PTR);
fn = Z_PTR_P(zv);
}
if (fn != NULL) {
if (fn->type == ZEND_INTERNAL_FUNCTION) {
flags |= zend_optimizer_classify_function(
Z_STR_P(zv), opline->extended_value);
fn->common.function_name, opline->extended_value);
}
}
break;
}
case ZEND_FAST_CALL:
BB_START(OP_JMP_ADDR(opline, opline->op1) - op_array->opcodes);
BB_START(i + 1);
Expand Down
9 changes: 9 additions & 0 deletions Zend/Optimizer/zend_dump.c
Original file line number Diff line number Diff line change
Expand Up @@ -679,6 +679,15 @@ ZEND_API void zend_dump_op(const zend_op_array *op_array, const zend_basic_block
}
} ZEND_HASH_FOREACH_END();
fprintf(stderr, " default:");
} else if (opline->opcode == ZEND_INIT_FCALL) {
zval *func_zv = CRT_CONSTANT(opline->op2);
if (Z_TYPE_P(func_zv) == IS_STRING) {
zend_dump_const(op);
} else {
ZEND_ASSERT(Z_TYPE_P(func_zv) == IS_PTR);
zend_function *func = Z_PTR_P(func_zv);
fprintf(stderr, " (%s)", ZSTR_VAL(func->common.function_name));
}
} else {
zend_dump_const(op);
}
Expand Down
18 changes: 14 additions & 4 deletions Zend/Optimizer/zend_optimizer.c
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,7 @@ bool zend_optimizer_update_op2_const(zend_op_array *op_array,
}
break;
case ZEND_INIT_FCALL:
ZEND_ASSERT(opline->op2_type == IS_CONST && Z_TYPE_P(CRT_CONSTANT(opline->op2)) == IS_STRING);
REQUIRES_STRING(val);
if (Z_REFCOUNT_P(val) == 1) {
zend_str_tolower(Z_STRVAL_P(val), Z_STRLEN_P(val));
Expand Down Expand Up @@ -838,7 +839,12 @@ zend_function *zend_optimizer_get_called_func(
switch (opline->opcode) {
case ZEND_INIT_FCALL:
{
zend_string *function_name = Z_STR_P(CRT_CONSTANT(opline->op2));
zval *func_zv = CRT_CONSTANT(opline->op2);
if (Z_TYPE_P(func_zv) == IS_PTR) {
return Z_PTR_P(func_zv);
}
ZEND_ASSERT(Z_TYPE_P(func_zv) == IS_STRING);
zend_string *function_name = Z_STR_P(func_zv);
zend_function *func;
if (script && (func = zend_hash_find_ptr(&script->function_table, function_name)) != NULL) {
return func;
Expand Down Expand Up @@ -1391,9 +1397,13 @@ static void zend_adjust_fcall_stack_size(zend_op_array *op_array, zend_optimizer
end = opline + op_array->last;
while (opline < end) {
if (opline->opcode == ZEND_INIT_FCALL) {
func = zend_hash_find_ptr(
&ctx->script->function_table,
Z_STR_P(RT_CONSTANT(opline, opline->op2)));
zval *func_zv = RT_CONSTANT(opline, opline->op2);
if (Z_TYPE_P(func_zv) == IS_STRING) {
func = zend_hash_find_ptr(&ctx->script->function_table, Z_STR_P(func_zv));
} else {
ZEND_ASSERT(Z_TYPE_P(func_zv) == IS_PTR);
func = Z_PTR_P(func_zv);
}
if (func) {
opline->op1.num = zend_vm_calc_used_stack(opline->extended_value, func);
}
Expand Down
9 changes: 9 additions & 0 deletions Zend/zend_compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -4837,7 +4837,16 @@ static void zend_compile_call(znode *result, zend_ast *ast, uint32_t type) /* {{
}

zval_ptr_dtor(&name_node.u.constant);
#if ZEND_VM_SPEC && !defined(ZEND_WIN32)
if (!(CG(compiler_options) & ZEND_COMPILE_WITH_FILE_CACHE)) {
zend_string_release_ex(lcname, 0);
ZVAL_PTR(&name_node.u.constant, fbc);
} else {
ZVAL_NEW_STR(&name_node.u.constant, lcname);
}
#else
ZVAL_NEW_STR(&name_node.u.constant, lcname);
#endif

opline = zend_emit_op(NULL, ZEND_INIT_FCALL, NULL, &name_node);
opline->result.num = zend_alloc_cache_slot();
Expand Down
36 changes: 36 additions & 0 deletions Zend/zend_vm_def.h
Original file line number Diff line number Diff line change
Expand Up @@ -3959,6 +3959,42 @@ ZEND_VM_HOT_HANDLER(61, ZEND_INIT_FCALL, NUM, CONST, NUM|CACHE_SLOT)
ZEND_VM_NEXT_OPCODE();
}

ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_INIT_FCALL, Z_TYPE_P(RT_CONSTANT(op, op->op2)) == IS_PTR && ((zend_function*)Z_PTR_P(RT_CONSTANT(op, op->op2)))->common.type == ZEND_INTERNAL_FUNCTION, ZEND_INIT_FCALL_PTR_INTERNAL, NUM, CONST, NUM|CACHE_SLOT)
{
USE_OPLINE
zend_function *fbc;
zend_execute_data *call;

fbc = Z_PTR_P(RT_CONSTANT(opline, opline->op2));
call = _zend_vm_stack_push_call_frame_ex(
opline->op1.num, ZEND_CALL_NESTED_FUNCTION,
fbc, opline->extended_value, NULL);
call->prev_execute_data = EX(call);
EX(call) = call;

ZEND_VM_NEXT_OPCODE();
}

ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_INIT_FCALL, Z_TYPE_P(RT_CONSTANT(op, op->op2)) == IS_PTR && ((zend_function*)Z_PTR_P(RT_CONSTANT(op, op->op2)))->common.type != ZEND_INTERNAL_FUNCTION, ZEND_INIT_FCALL_PTR_USER, NUM, CONST, NUM|CACHE_SLOT)
{
USE_OPLINE
zend_function *fbc;
zend_execute_data *call;

fbc = Z_PTR_P(RT_CONSTANT(opline, opline->op2));
if (UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) {
init_func_run_time_cache(&fbc->op_array);
}

call = _zend_vm_stack_push_call_frame_ex(
opline->op1.num, ZEND_CALL_NESTED_FUNCTION,
fbc, opline->extended_value, NULL);
call->prev_execute_data = EX(call);
EX(call) = call;

ZEND_VM_NEXT_OPCODE();
}

ZEND_VM_HOT_HANDLER(129, ZEND_DO_ICALL, ANY, ANY, SPEC(RETVAL,OBSERVER))
{
USE_OPLINE
Expand Down
Loading