Skip to content

Commit 1a63fa6

Browse files
committed
Implemented Request #76178 (Class constants are slow: they should be inlined at runtime)
Run-time cache is used to eliminate recalculation of constant expression in RECV_INIT opcode (only non reference countable values are cached).
1 parent 5a31e14 commit 1a63fa6

File tree

5 files changed

+75
-14
lines changed

5 files changed

+75
-14
lines changed

Zend/zend_opcode.c

+10
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,16 @@ ZEND_API int pass_two(zend_op_array *op_array)
579579
end = opline + op_array->last;
580580
while (opline < end) {
581581
switch (opline->opcode) {
582+
case ZEND_RECV_INIT:
583+
{
584+
zval *val = CT_CONSTANT(opline->op2);
585+
if (Z_TYPE_P(val) == IS_CONSTANT_AST) {
586+
uint32_t slot = ZEND_MM_ALIGNED_SIZE_EX(op_array->cache_size, 8);
587+
Z_CACHE_SLOT_P(val) = slot;
588+
op_array->cache_size += sizeof(zval);
589+
}
590+
}
591+
break;
582592
case ZEND_FAST_CALL:
583593
opline->op1.opline_num = op_array->try_catch_array[opline->op1.num].finally_op;
584594
ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, opline->op1);

Zend/zend_types.h

+4
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@ struct _zval_struct {
192192
} u1;
193193
union {
194194
uint32_t next; /* hash collision chain */
195+
uint32_t cache_slot; /* cache slot (for RECV_INIT) */
195196
uint32_t opline_num; /* opline number (for FAST_CALL) */
196197
uint32_t lineno; /* line number (for ast nodes) */
197198
uint32_t num_args; /* arguments number for EX(This) */
@@ -404,6 +405,9 @@ static zend_always_inline zend_uchar zval_get_type(const zval* pz) {
404405
#define Z_NEXT(zval) (zval).u2.next
405406
#define Z_NEXT_P(zval_p) Z_NEXT(*(zval_p))
406407

408+
#define Z_CACHE_SLOT(zval) (zval).u2.cache_slot
409+
#define Z_CACHE_SLOT_P(zval_p) Z_CACHE_SLOT(*(zval_p))
410+
407411
#define Z_LINENO(zval) (zval).u2.lineno
408412
#define Z_LINENO_P(zval_p) Z_LINENO(*(zval_p))
409413

Zend/zend_vm_def.h

+21-7
Original file line numberDiff line numberDiff line change
@@ -4724,14 +4724,28 @@ ZEND_VM_HOT_HANDLER(64, ZEND_RECV_INIT, NUM, CONST, CACHE_SLOT)
47244724
arg_num = opline->op1.num;
47254725
param = _get_zval_ptr_cv_undef_BP_VAR_W(opline->result.var EXECUTE_DATA_CC);
47264726
if (arg_num > EX_NUM_ARGS()) {
4727-
ZVAL_COPY(param, RT_CONSTANT(opline, opline->op2));
4728-
if (Z_OPT_TYPE_P(param) == IS_CONSTANT_AST) {
4729-
SAVE_OPLINE();
4730-
if (UNEXPECTED(zval_update_constant_ex(param, EX(func)->op_array.scope) != SUCCESS)) {
4731-
zval_ptr_dtor_nogc(param);
4732-
ZVAL_UNDEF(param);
4733-
HANDLE_EXCEPTION();
4727+
zval *default_value = RT_CONSTANT(opline, opline->op2);
4728+
4729+
if (Z_OPT_TYPE_P(default_value) == IS_CONSTANT_AST) {
4730+
zval *cache_val = (zval*)CACHE_ADDR(Z_CACHE_SLOT_P(default_value));
4731+
4732+
/* we keep in cache only not refcounted values */
4733+
if (Z_TYPE_P(cache_val) != IS_UNDEF) {
4734+
ZVAL_COPY_VALUE(param, cache_val);
4735+
} else {
4736+
SAVE_OPLINE();
4737+
ZVAL_COPY(param, default_value);
4738+
if (UNEXPECTED(zval_update_constant_ex(param, EX(func)->op_array.scope) != SUCCESS)) {
4739+
zval_ptr_dtor_nogc(param);
4740+
ZVAL_UNDEF(param);
4741+
HANDLE_EXCEPTION();
4742+
}
4743+
if (!Z_REFCOUNTED_P(param)) {
4744+
ZVAL_COPY_VALUE(cache_val, param);
4745+
}
47344746
}
4747+
} else {
4748+
ZVAL_COPY(param, default_value);
47354749
}
47364750
}
47374751

Zend/zend_vm_execute.h

+21-7
Original file line numberDiff line numberDiff line change
@@ -2237,14 +2237,28 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_RECV_INIT_SPEC_CON
22372237
arg_num = opline->op1.num;
22382238
param = _get_zval_ptr_cv_undef_BP_VAR_W(opline->result.var EXECUTE_DATA_CC);
22392239
if (arg_num > EX_NUM_ARGS()) {
2240-
ZVAL_COPY(param, RT_CONSTANT(opline, opline->op2));
2241-
if (Z_OPT_TYPE_P(param) == IS_CONSTANT_AST) {
2242-
SAVE_OPLINE();
2243-
if (UNEXPECTED(zval_update_constant_ex(param, EX(func)->op_array.scope) != SUCCESS)) {
2244-
zval_ptr_dtor_nogc(param);
2245-
ZVAL_UNDEF(param);
2246-
HANDLE_EXCEPTION();
2240+
zval *default_value = RT_CONSTANT(opline, opline->op2);
2241+
2242+
if (Z_OPT_TYPE_P(default_value) == IS_CONSTANT_AST) {
2243+
zval *cache_val = (zval*)CACHE_ADDR(Z_CACHE_SLOT_P(default_value));
2244+
2245+
/* we keep in cache only not refcounted values */
2246+
if (Z_TYPE_P(cache_val) != IS_UNDEF) {
2247+
ZVAL_COPY_VALUE(param, cache_val);
2248+
} else {
2249+
SAVE_OPLINE();
2250+
ZVAL_COPY(param, default_value);
2251+
if (UNEXPECTED(zval_update_constant_ex(param, EX(func)->op_array.scope) != SUCCESS)) {
2252+
zval_ptr_dtor_nogc(param);
2253+
ZVAL_UNDEF(param);
2254+
HANDLE_EXCEPTION();
2255+
}
2256+
if (!Z_REFCOUNTED_P(param)) {
2257+
ZVAL_COPY_VALUE(cache_val, param);
2258+
}
22472259
}
2260+
} else {
2261+
ZVAL_COPY(param, default_value);
22482262
}
22492263
}
22502264

ext/opcache/Optimizer/compact_literals.c

+19
Original file line numberDiff line numberDiff line change
@@ -740,6 +740,25 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
740740
zend_hash_destroy(&hash);
741741
zend_arena_release(&ctx->arena, checkpoint);
742742

743+
if (1) {
744+
opline = op_array->opcodes;
745+
while (1) {
746+
if (opline->opcode == ZEND_RECV_INIT) {
747+
zval *val = &op_array->literals[opline->op2.constant];
748+
749+
if (Z_TYPE_P(val) == IS_CONSTANT_AST) {
750+
uint32_t slot = ZEND_MM_ALIGNED_SIZE_EX(op_array->cache_size, 8);
751+
752+
Z_CACHE_SLOT_P(val) = slot;
753+
op_array->cache_size += sizeof(zval);
754+
}
755+
} else if (opline->opcode != ZEND_RECV) {
756+
break;
757+
}
758+
opline++;
759+
}
760+
}
761+
743762
#if DEBUG_COMPACT_LITERALS
744763
{
745764
int i, use_copy;

0 commit comments

Comments
 (0)