Run-time cache is used to eliminate recalculation of constant expression in RECV_INIT opcode (only non reference countable values are cached).
end = opline + op_array->last;
while (opline < end) {
switch (opline->opcode) {
+ case ZEND_RECV_INIT:
+ {
+ zval *val = CT_CONSTANT(opline->op2);
+ if (Z_TYPE_P(val) == IS_CONSTANT_AST) {
+ uint32_t slot = ZEND_MM_ALIGNED_SIZE_EX(op_array->cache_size, 8);
+ Z_CACHE_SLOT_P(val) = slot;
+ op_array->cache_size += sizeof(zval);
+ }
+ }
+ break;
case ZEND_FAST_CALL:
opline->op1.opline_num = op_array->try_catch_array[opline->op1.num].finally_op;
ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, opline->op1);
} u1;
union {
uint32_t next; /* hash collision chain */
+ uint32_t cache_slot; /* cache slot (for RECV_INIT) */
uint32_t opline_num; /* opline number (for FAST_CALL) */
uint32_t lineno; /* line number (for ast nodes) */
uint32_t num_args; /* arguments number for EX(This) */
#define Z_NEXT(zval) (zval).u2.next
#define Z_NEXT_P(zval_p) Z_NEXT(*(zval_p))
+#define Z_CACHE_SLOT(zval) (zval).u2.cache_slot
+#define Z_CACHE_SLOT_P(zval_p) Z_CACHE_SLOT(*(zval_p))
+
#define Z_LINENO(zval) (zval).u2.lineno
#define Z_LINENO_P(zval_p) Z_LINENO(*(zval_p))
arg_num = opline->op1.num;
param = _get_zval_ptr_cv_undef_BP_VAR_W(opline->result.var EXECUTE_DATA_CC);
if (arg_num > EX_NUM_ARGS()) {
- ZVAL_COPY(param, RT_CONSTANT(opline, opline->op2));
- if (Z_OPT_TYPE_P(param) == IS_CONSTANT_AST) {
- SAVE_OPLINE();
- if (UNEXPECTED(zval_update_constant_ex(param, EX(func)->op_array.scope) != SUCCESS)) {
- zval_ptr_dtor_nogc(param);
- ZVAL_UNDEF(param);
- HANDLE_EXCEPTION();
+ zval *default_value = RT_CONSTANT(opline, opline->op2);
+
+ if (Z_OPT_TYPE_P(default_value) == IS_CONSTANT_AST) {
+ zval *cache_val = (zval*)CACHE_ADDR(Z_CACHE_SLOT_P(default_value));
+
+ /* we keep in cache only not refcounted values */
+ if (Z_TYPE_P(cache_val) != IS_UNDEF) {
+ ZVAL_COPY_VALUE(param, cache_val);
+ } else {
+ SAVE_OPLINE();
+ ZVAL_COPY(param, default_value);
+ if (UNEXPECTED(zval_update_constant_ex(param, EX(func)->op_array.scope) != SUCCESS)) {
+ zval_ptr_dtor_nogc(param);
+ ZVAL_UNDEF(param);
+ HANDLE_EXCEPTION();
+ }
+ if (!Z_REFCOUNTED_P(param)) {
+ ZVAL_COPY_VALUE(cache_val, param);
+ }
}
+ } else {
+ ZVAL_COPY(param, default_value);
}
}
arg_num = opline->op1.num;
param = _get_zval_ptr_cv_undef_BP_VAR_W(opline->result.var EXECUTE_DATA_CC);
if (arg_num > EX_NUM_ARGS()) {
- ZVAL_COPY(param, RT_CONSTANT(opline, opline->op2));
- if (Z_OPT_TYPE_P(param) == IS_CONSTANT_AST) {
- SAVE_OPLINE();
- if (UNEXPECTED(zval_update_constant_ex(param, EX(func)->op_array.scope) != SUCCESS)) {
- zval_ptr_dtor_nogc(param);
- ZVAL_UNDEF(param);
- HANDLE_EXCEPTION();
+ zval *default_value = RT_CONSTANT(opline, opline->op2);
+
+ if (Z_OPT_TYPE_P(default_value) == IS_CONSTANT_AST) {
+ zval *cache_val = (zval*)CACHE_ADDR(Z_CACHE_SLOT_P(default_value));
+
+ /* we keep in cache only not refcounted values */
+ if (Z_TYPE_P(cache_val) != IS_UNDEF) {
+ ZVAL_COPY_VALUE(param, cache_val);
+ } else {
+ SAVE_OPLINE();
+ ZVAL_COPY(param, default_value);
+ if (UNEXPECTED(zval_update_constant_ex(param, EX(func)->op_array.scope) != SUCCESS)) {
+ zval_ptr_dtor_nogc(param);
+ ZVAL_UNDEF(param);
+ HANDLE_EXCEPTION();
+ }
+ if (!Z_REFCOUNTED_P(param)) {
+ ZVAL_COPY_VALUE(cache_val, param);
+ }
}
+ } else {
+ ZVAL_COPY(param, default_value);
}
}
zend_hash_destroy(&hash);
zend_arena_release(&ctx->arena, checkpoint);
+ if (1) {
+ opline = op_array->opcodes;
+ while (1) {
+ if (opline->opcode == ZEND_RECV_INIT) {
+ zval *val = &op_array->literals[opline->op2.constant];
+
+ if (Z_TYPE_P(val) == IS_CONSTANT_AST) {
+ uint32_t slot = ZEND_MM_ALIGNED_SIZE_EX(op_array->cache_size, 8);
+
+ Z_CACHE_SLOT_P(val) = slot;
+ op_array->cache_size += sizeof(zval);
+ }
+ } else if (opline->opcode != ZEND_RECV) {
+ break;
+ }
+ opline++;
+ }
+ }
+
#if DEBUG_COMPACT_LITERALS
{
int i, use_copy;