Skip to content

Commit 33e41e7

Browse files
committed
Share JMP_FRAMELESS & INIT_NS_FCALL_BY_NAME cache slots
1 parent c719149 commit 33e41e7

10 files changed

+83
-62
lines changed

Zend/Optimizer/compact_literals.c

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,9 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
181181
case ZEND_INIT_NS_FCALL_BY_NAME:
182182
LITERAL_INFO(opline->op2.constant, 3);
183183
break;
184+
case ZEND_JMP_FRAMELESS:
185+
LITERAL_INFO(opline->op1.constant, 3);
186+
break;
184187
case ZEND_INIT_METHOD_CALL:
185188
if (opline->op1_type == IS_CONST) {
186189
LITERAL_INFO(opline->op1.constant, 1);
@@ -610,6 +613,16 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
610613
func_slot[opline->op2.constant] = opline->result.num;
611614
}
612615
break;
616+
case ZEND_JMP_FRAMELESS:
617+
// op1 func
618+
if (func_slot[opline->op1.constant] >= 0) {
619+
opline->extended_value = func_slot[opline->op1.constant];
620+
} else {
621+
opline->extended_value = cache_size;
622+
cache_size += sizeof(void *);
623+
func_slot[opline->op1.constant] = opline->extended_value;
624+
}
625+
break;
613626
case ZEND_INIT_METHOD_CALL:
614627
if (opline->op2_type == IS_CONST) {
615628
// op2 method
@@ -770,7 +783,6 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
770783
break;
771784
case ZEND_DECLARE_ANON_CLASS:
772785
case ZEND_DECLARE_CLASS_DELAYED:
773-
case ZEND_JMP_FRAMELESS:
774786
opline->extended_value = cache_size;
775787
cache_size += sizeof(void *);
776788
break;

Zend/tests/frameless_jmp_004.phpt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,9 @@ function declare_local_class_exists() {
99
return true;
1010
}
1111
}
12-
var_dump(CLASS_EXISTS('Foo'));
1312
declare_local_class_exists();
1413
var_dump(CLASS_EXISTS('Foo'));
1514
?>
1615
--EXPECT--
17-
bool(false)
1816
string(16) "Foo\class_exists"
1917
bool(true)

Zend/zend_compile.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4611,6 +4611,7 @@ static uint32_t zend_compile_frameless_icall(znode *result, zend_ast_list *args,
46114611
static void zend_compile_ns_call(znode *result, znode *name_node, zend_ast *args_ast, uint32_t lineno, uint32_t type) /* {{{ */
46124612
{
46134613
int name_constants = zend_add_ns_func_name_literal(Z_STR(name_node->u.constant));
4614+
uint32_t cache_slot = zend_alloc_cache_slot();
46144615

46154616
/* Find frameless function with same name. */
46164617
zend_function *frameless_function = NULL;
@@ -4626,11 +4627,11 @@ static void zend_compile_ns_call(znode *result, znode *name_node, zend_ast *args
46264627
if (frameless_function) {
46274628
frameless_function_info = find_frameless_function_info(zend_ast_get_list(args_ast), frameless_function, type);
46284629
if (frameless_function_info) {
4629-
znode op1;
4630-
op1.op_type = IS_CONST;
4631-
ZVAL_COPY(&op1.u.constant, CT_CONSTANT_EX(CG(active_op_array), name_constants + 1));
46324630
jmp_fl_opnum = get_next_op_number();
4633-
zend_emit_op(NULL, ZEND_JMP_FRAMELESS, &op1, NULL);
4631+
zend_op *jmp_fl = zend_emit_op(NULL, ZEND_JMP_FRAMELESS, NULL, NULL);
4632+
jmp_fl->op1_type = IS_CONST;
4633+
jmp_fl->op1.num = name_constants;
4634+
jmp_fl->extended_value = cache_slot;
46344635
}
46354636
}
46364637

@@ -4639,7 +4640,7 @@ static void zend_compile_ns_call(znode *result, znode *name_node, zend_ast *args
46394640
opline->opcode = ZEND_INIT_NS_FCALL_BY_NAME;
46404641
opline->op2_type = IS_CONST;
46414642
opline->op2.constant = name_constants;
4642-
opline->result.num = zend_alloc_cache_slot();
4643+
opline->result.num = cache_slot;
46434644
zend_compile_call_common(result, args_ast, NULL, lineno);
46444645

46454646
/* Compile frameless call. */
@@ -4651,7 +4652,6 @@ static void zend_compile_ns_call(znode *result, znode *name_node, zend_ast *args
46514652

46524653
zend_op *jmp_fl = &CG(active_op_array)->opcodes[jmp_fl_opnum];
46534654
jmp_fl->op2.opline_num = jmp_fl_target;
4654-
jmp_fl->extended_value = zend_alloc_cache_slot();
46554655
zend_op *flf_icall = &CG(active_op_array)->opcodes[flf_icall_opnum];
46564656
SET_NODE(flf_icall->result, result);
46574657
zend_update_jump_target_to_next(jmp_end_opnum);

Zend/zend_frameless_function.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -122,12 +122,6 @@ typedef struct {
122122
uint32_t num_args;
123123
} zend_frameless_function_info;
124124

125-
typedef enum {
126-
ZEND_JMP_FL_UNPRIMED = 0,
127-
ZEND_JMP_FL_MISS = 1,
128-
ZEND_JMP_FL_HIT = 2,
129-
} zend_jmp_fl_result;
130-
131125
END_EXTERN_C()
132126

133127
#endif

Zend/zend_vm_def.h

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9559,23 +9559,32 @@ ZEND_VM_HANDLER(202, ZEND_CALLABLE_CONVERT, UNUSED, UNUSED)
95599559
ZEND_VM_HANDLER(208, ZEND_JMP_FRAMELESS, CONST, JMP_ADDR, NUM|CACHE_SLOT)
95609560
{
95619561
USE_OPLINE
9562-
zend_jmp_fl_result result = (uintptr_t)CACHED_PTR(opline->extended_value);
9563-
ZEND_VM_C_LABEL(try_again):
9564-
if (EXPECTED(result == ZEND_JMP_FL_HIT)) {
9562+
zend_function *fbc;
9563+
9564+
fbc = CACHED_PTR(opline->extended_value);
9565+
9566+
if (UNEXPECTED(fbc == NULL)) {
9567+
/* E.g. foo\substr. */
9568+
zval *local_func_name = (zval *)RT_CONSTANT(opline, opline->op1) + 1;
9569+
/* If it cannot be found locally, we must be referring to the global function. */
9570+
zval *func = zend_hash_find_known_hash(EG(function_table), Z_STR_P(local_func_name));
9571+
if (UNEXPECTED(!func)) {
9572+
/* E.g. substr. */
9573+
zval *global_func_name = (zval *)RT_CONSTANT(opline, opline->op1) + 2;
9574+
func = zend_hash_find_known_hash(EG(function_table), Z_STR_P(global_func_name));
9575+
}
9576+
ZEND_ASSERT(func);
9577+
fbc = Z_FUNC_P(func);
9578+
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) {
9579+
init_func_run_time_cache(&fbc->op_array);
9580+
}
9581+
CACHE_PTR(opline->extended_value, fbc);
9582+
}
9583+
if (EXPECTED(fbc->type == ZEND_INTERNAL_FUNCTION)) {
95659584
OPLINE = OP_JMP_ADDR(opline, opline->op2);
95669585
ZEND_VM_CONTINUE();
9567-
} else if (EXPECTED(result == ZEND_JMP_FL_MISS)) {
9568-
ZEND_VM_NEXT_OPCODE();
95699586
} else {
9570-
ZEND_ASSERT(result == ZEND_JMP_FL_UNPRIMED);
9571-
/* func_name refers to the function in the local namespace, e.g. foo\substr. */
9572-
zval *func_name = (zval *)RT_CONSTANT(opline, opline->op1);
9573-
/* If it cannot be found locally, we must be referring to the global function. */
9574-
zval *func = zend_hash_find_known_hash(EG(function_table), Z_STR_P(func_name));
9575-
/* ZEND_JMP_FL_MISS = 1, ZEND_JMP_FL_HIT = 2 */
9576-
result = (func == NULL) + 1;
9577-
CACHE_PTR(opline->extended_value, (void *)result);
9578-
ZEND_VM_C_GOTO(try_again);
9587+
ZEND_VM_NEXT_OPCODE();
95799588
}
95809589
}
95819590

Zend/zend_vm_execute.h

Lines changed: 23 additions & 14 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ext/opcache/jit/zend_jit.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2560,7 +2560,7 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op
25602560
}
25612561
break;
25622562
case ZEND_JMP_FRAMELESS:
2563-
if (!zend_jit_jmp_frameless(&ctx, opline, /* exit_addr */ NULL, /* guard */ 0)) {
2563+
if (!zend_jit_jmp_frameless(&ctx, opline, /* exit_addr */ NULL, /* guard_frameless */ false)) {
25642564
goto jit_failure;
25652565
}
25662566
break;

ext/opcache/jit/zend_jit_helpers.c

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -67,14 +67,6 @@ static zend_function* ZEND_FASTCALL zend_jit_find_func_helper(zend_string *name,
6767
return fbc;
6868
}
6969

70-
static uint32_t ZEND_FASTCALL zend_jit_jmp_frameless_helper(zval *func_name, void **cache_slot)
71-
{
72-
zval *func = zend_hash_find_known_hash(EG(function_table), Z_STR_P(func_name));
73-
zend_jmp_fl_result result = (func == NULL) + 1;
74-
*cache_slot = (void *)(uintptr_t)result;
75-
return result;
76-
}
77-
7870
static zend_function* ZEND_FASTCALL zend_jit_find_ns_func_helper(zval *func_name, void **cache_slot)
7971
{
8072
zval *func = zend_hash_find_known_hash(EG(function_table), Z_STR_P(func_name + 1));

ext/opcache/jit/zend_jit_ir.c

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2997,7 +2997,6 @@ static void zend_jit_setup_disasm(void)
29972997
REGISTER_HELPER(zend_jit_init_func_run_time_cache_helper);
29982998
REGISTER_HELPER(zend_jit_find_func_helper);
29992999
REGISTER_HELPER(zend_jit_find_ns_func_helper);
3000-
REGISTER_HELPER(zend_jit_jmp_frameless_helper);
30013000
REGISTER_HELPER(zend_jit_unref_helper);
30023001
REGISTER_HELPER(zend_jit_invalid_method_call);
30033002
REGISTER_HELPER(zend_jit_invalid_method_call_tmp);
@@ -3781,7 +3780,7 @@ static int zend_jit_jmp_frameless(
37813780
zend_jit_ctx *jit,
37823781
const zend_op *opline,
37833782
const void *exit_addr,
3784-
zend_jmp_fl_result guard
3783+
bool guard_frameless
37853784
) {
37863785
ir_ref ref, if_ref, cache_result, function_result, phi_result, cache_slot_ref;
37873786
zend_basic_block *bb;
@@ -3794,20 +3793,28 @@ static int zend_jit_jmp_frameless(
37943793
if_ref = ir_IF(cache_result);
37953794
ir_IF_FALSE_cold(if_ref);
37963795
zval *func_name_zv = RT_CONSTANT(opline, opline->op1);
3797-
function_result = ir_CALL_2(IR_LONG, ir_CONST_FC_FUNC(zend_jit_jmp_frameless_helper),
3796+
function_result = ir_CALL_2(IR_LONG, ir_CONST_FC_FUNC(zend_jit_find_ns_func_helper),
37983797
ir_CONST_ADDR(func_name_zv),
37993798
cache_slot_ref);
38003799
ir_MERGE_WITH_EMPTY_TRUE(if_ref);
38013800

38023801
phi_result = ir_PHI_2(IR_LONG, function_result, cache_result);
38033802

3803+
// JIT: func_type = func->type
3804+
ir_ref func_type = ir_LOAD_U8(ir_ADD_OFFSET(phi_result, offsetof(zend_function, type)));
3805+
38043806
if (exit_addr) {
3805-
ir_GUARD(ir_EQ(phi_result, ir_CONST_LONG(guard)), ir_CONST_ADDR(exit_addr));
3807+
ir_ref is_internal_ref = ir_EQ(func_type, ir_CONST_U8(ZEND_INTERNAL_FUNCTION));
3808+
if (guard_frameless) {
3809+
ir_GUARD(is_internal_ref, ir_CONST_ADDR(exit_addr));
3810+
} else {
3811+
ir_GUARD_NOT(is_internal_ref, ir_CONST_ADDR(exit_addr));
3812+
}
38063813
} else {
38073814
ZEND_ASSERT(jit->b >= 0);
38083815
bb = &jit->ssa->cfg.blocks[jit->b];
3809-
// JIT: if (result == ZEND_JMP_FL_HIT)
3810-
ref = jit_IF_ex(jit, ir_EQ(phi_result, ir_CONST_LONG(ZEND_JMP_FL_HIT)), bb->successors[0]);
3816+
// JIT: if (func_type == ZEND_INTERNAL_FUNCTION) {
3817+
ref = jit_IF_ex(jit, ir_EQ(func_type, ir_CONST_U8(ZEND_INTERNAL_FUNCTION)), bb->successors[0]);
38113818
_zend_jit_add_predecessor_ref(jit, bb->successors[0], jit->b, ref);
38123819
_zend_jit_add_predecessor_ref(jit, bb->successors[1], jit->b, ref);
38133820
jit->b = -1;

ext/opcache/jit/zend_jit_trace.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5567,15 +5567,15 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
55675567
ZEND_ASSERT((p+1)->op == ZEND_JIT_TRACE_VM);
55685568
const zend_op *exit_opline = NULL;
55695569
uint32_t exit_point;
5570-
zend_jmp_fl_result guard;
5570+
bool guard_frameless;
55715571

55725572
if ((p+1)->opline == OP_JMP_ADDR(opline, opline->op2)) {
55735573
/* taken branch */
5574-
guard = ZEND_JMP_FL_HIT;
5574+
guard_frameless = true;
55755575
exit_opline = opline + 1;
55765576
} else if ((p+1)->opline == opline + 1) {
55775577
/* not taken branch */
5578-
guard = ZEND_JMP_FL_MISS;
5578+
guard_frameless = false;
55795579
exit_opline = OP_JMP_ADDR(opline, opline->op2);
55805580
} else {
55815581
ZEND_UNREACHABLE();
@@ -5585,7 +5585,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
55855585
if (!exit_addr) {
55865586
goto jit_failure;
55875587
}
5588-
if (!zend_jit_jmp_frameless(&ctx, opline, exit_addr, guard)) {
5588+
if (!zend_jit_jmp_frameless(&ctx, opline, exit_addr, guard_frameless)) {
55895589
goto jit_failure;
55905590
}
55915591
goto done;

0 commit comments

Comments
 (0)