From: Dmitry Stogov Date: Wed, 15 Jul 2020 14:28:46 +0000 (+0300) Subject: Check type guard on result of FETCH_DIM_R/IS instructions X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=f74e9a4dd35a92627f3195d94ce8952e46b5d479;p=php Check type guard on result of FETCH_DIM_R/IS instructions --- diff --git a/ext/opcache/jit/zend_jit_internal.h b/ext/opcache/jit/zend_jit_internal.h index 6c47547034..7dd8786fde 100644 --- a/ext/opcache/jit/zend_jit_internal.h +++ b/ext/opcache/jit/zend_jit_internal.h @@ -208,6 +208,8 @@ typedef enum _zend_jit_trace_stop { #define ZEND_JIT_EXIT_TO_VM (1<<2) /* exit to VM without attempt to create a side trace */ #define ZEND_JIT_EXIT_RESTORE_CALL (1<<3) /* deoptimizer should restore EX(call) chain */ #define ZEND_JIT_EXIT_POLYMORPHISM (1<<4) /* exit because of polymorphic call */ +#define ZEND_JIT_EXIT_FREE_OP1 (1<<5) +#define ZEND_JIT_EXIT_FREE_OP2 (1<<6) typedef union _zend_op_trace_info { zend_op dummy; /* the size of this structure must be the same as zend_op */ diff --git a/ext/opcache/jit/zend_jit_trace.c b/ext/opcache/jit/zend_jit_trace.c index 655bcbc2b2..a5bc5f34af 100644 --- a/ext/opcache/jit/zend_jit_trace.c +++ b/ext/opcache/jit/zend_jit_trace.c @@ -146,7 +146,8 @@ static uint32_t zend_jit_trace_get_exit_point(const zend_op *from_opline, const if (stack_size) { stack = JIT_G(current_frame)->stack; do { - if (STACK_TYPE(stack, stack_size-1) != IS_UNKNOWN) { + if (STACK_TYPE(stack, stack_size-1) != IS_UNKNOWN + || STACK_REG(stack, stack_size-1) != ZREG_NONE) { break; } stack_size--; @@ -2832,17 +2833,37 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par goto jit_failure; } } else { - SET_STACK_REG(stack, i, ZREG_NONE); + if (STACK_REG(parent_stack, i) == ZREG_ZVAL_COPY_R0) { + SET_STACK_TYPE(stack, i, IS_UNKNOWN); + } else { + SET_STACK_REG(stack, i, ZREG_NONE); + } if (!zend_jit_store_const(&dasm_state, i, STACK_REG(parent_stack, i))) { goto jit_failure; } } } } - if (zend_jit_traces[parent_trace].exit_info[exit_num].flags & ZEND_JIT_EXIT_RESTORE_CALL) { zend_jit_save_call_chain(&dasm_state, -1); } + if (zend_jit_traces[parent_trace].exit_info[exit_num].flags & ZEND_JIT_EXIT_FREE_OP2) { + const zend_op *op = zend_jit_traces[parent_trace].exit_info[exit_num].opline - 1; + if (!zend_jit_free_op(&dasm_state, op, -1, op->op2.var)) { + goto jit_failure; + } + } + if (zend_jit_traces[parent_trace].exit_info[exit_num].flags & ZEND_JIT_EXIT_FREE_OP1) { + const zend_op *op = zend_jit_traces[parent_trace].exit_info[exit_num].opline - 1; + if (!zend_jit_free_op(&dasm_state, op, -1, op->op1.var)) { + goto jit_failure; + } + } + if (zend_jit_traces[parent_trace].exit_info[exit_num].flags & (ZEND_JIT_EXIT_FREE_OP1|ZEND_JIT_EXIT_FREE_OP2)) { + if (!zend_jit_check_exception(&dasm_state)) { + goto jit_failure; + } + } } if (ra @@ -3750,6 +3771,11 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par (op2_info & (MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY)) != 0)))) { goto jit_failure; } + if ((res_info & MAY_BE_GUARD) + && JIT_G(current_frame) + && (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY) { + ssa->var_info[ssa_op->result_def].type &= ~MAY_BE_GUARD; + } goto done; case ZEND_ISSET_ISEMPTY_DIM_OBJ: if ((opline->extended_value & ZEND_ISEMPTY)) { @@ -4598,6 +4624,21 @@ static const void *zend_jit_trace_exit_to_vm(uint32_t trace_num, uint32_t exit_n opline = zend_jit_traces[trace_num].exit_info[exit_num].opline; if (opline) { + if (zend_jit_traces[trace_num].exit_info[exit_num].flags & ZEND_JIT_EXIT_FREE_OP2) { + if (!zend_jit_free_op(&dasm_state, (opline-1), -1, (opline-1)->op2.var)) { + goto jit_failure; + } + } + if (zend_jit_traces[trace_num].exit_info[exit_num].flags & ZEND_JIT_EXIT_FREE_OP1) { + if (!zend_jit_free_op(&dasm_state, (opline-1), -1, (opline-1)->op1.var)) { + goto jit_failure; + } + } + if (zend_jit_traces[trace_num].exit_info[exit_num].flags & (ZEND_JIT_EXIT_FREE_OP1|ZEND_JIT_EXIT_FREE_OP2)) { + if (!zend_jit_check_exception(&dasm_state)) { + goto jit_failure; + } + } zend_jit_set_ip(&dasm_state, opline); if (opline == zend_jit_traces[zend_jit_traces[trace_num].root].opline) { /* prevent endless loop */ @@ -4995,6 +5036,12 @@ static void zend_jit_dump_exit_info(zend_jit_trace_info *t) if (t->exit_info[i].flags & ZEND_JIT_EXIT_POLYMORPHISM) { fprintf(stderr, "/POLY"); } + if (t->exit_info[i].flags & ZEND_JIT_EXIT_FREE_OP1) { + fprintf(stderr, "/FREE_OP1"); + } + if (t->exit_info[i].flags & ZEND_JIT_EXIT_FREE_OP2) { + fprintf(stderr, "/FREE_OP2"); + } for (j = 0; j < stack_size; j++) { zend_uchar type = STACK_TYPE(stack, j); if (type != IS_UNKNOWN) { @@ -5005,16 +5052,18 @@ static void zend_jit_dump_exit_info(zend_jit_trace_info *t) fprintf(stderr, "undef"); } else { fprintf(stderr, "%s", zend_get_type_by_const(type)); - if (STACK_REG(stack, j) != ZREG_NONE) { - if (STACK_REG(stack, j) < ZREG_NUM) { - fprintf(stderr, "(%s)", zend_reg_name[STACK_REG(stack, j)]); - } else if (STACK_REG(stack, j) == ZREG_THIS) { - fprintf(stderr, "(this)"); - } else { - fprintf(stderr, "(const_%d)", STACK_REG(stack, j) - ZREG_NUM); - } + } + if (STACK_REG(stack, j) != ZREG_NONE) { + if (STACK_REG(stack, j) < ZREG_NUM) { + fprintf(stderr, "(%s)", zend_reg_name[STACK_REG(stack, j)]); + } else if (STACK_REG(stack, j) == ZREG_THIS) { + fprintf(stderr, "(this)"); + } else { + fprintf(stderr, "(const_%d)", STACK_REG(stack, j) - ZREG_NUM); } } + } else if (STACK_REG(stack, j) == ZREG_ZVAL_COPY_R0) { + fprintf(stderr, " zval_copy(%s)", zend_reg_name[0]); } } fprintf(stderr, "\n"); @@ -5477,6 +5526,12 @@ int ZEND_FASTCALL zend_jit_trace_exit(uint32_t exit_num, zend_jit_registers_buf GC_ADDREF(obj); ZVAL_OBJ(EX_VAR_NUM(i), obj); + } else if (STACK_REG(stack, i) == ZREG_NULL) { + ZVAL_NULL(EX_VAR_NUM(i)); + } else if (STACK_REG(stack, i) == ZREG_ZVAL_COPY_R0) { + zval *val = (zval*)regs->r[0]; + + ZVAL_COPY(EX_VAR_NUM(i), val); } else { ZEND_UNREACHABLE(); } @@ -5484,7 +5539,28 @@ int ZEND_FASTCALL zend_jit_trace_exit(uint32_t exit_num, zend_jit_registers_buf } opline = t->exit_info[exit_num].opline; + if (opline) { + if (t->exit_info[exit_num].flags & ZEND_JIT_EXIT_FREE_OP2) { + ZEND_ASSERT((opline-1)->opcode == ZEND_FETCH_DIM_R + || (opline-1)->opcode == ZEND_FETCH_DIM_IS + || (opline-1)->opcode == ZEND_FETCH_DIM_FUNC_ARG); + EX(opline) = opline-1; + zval_ptr_dtor_nogc(EX_VAR((opline-1)->op2.var)); + } + if (t->exit_info[exit_num].flags & ZEND_JIT_EXIT_FREE_OP1) { + ZEND_ASSERT((opline-1)->opcode == ZEND_FETCH_DIM_R + || (opline-1)->opcode == ZEND_FETCH_DIM_IS + || (opline-1)->opcode == ZEND_FETCH_DIM_FUNC_ARG); + EX(opline) = opline-1; + zval_ptr_dtor_nogc(EX_VAR((opline-1)->op1.var)); + } + if (t->exit_info[exit_num].flags & (ZEND_JIT_EXIT_FREE_OP1|ZEND_JIT_EXIT_FREE_OP2)) { + if (EG(exception)) { + return 1; + } + } + /* Set VM opline to continue interpretation */ EX(opline) = opline; } diff --git a/ext/opcache/jit/zend_jit_x86.dasc b/ext/opcache/jit/zend_jit_x86.dasc index 2bc4da07a4..9508cd3fa7 100644 --- a/ext/opcache/jit/zend_jit_x86.dasc +++ b/ext/opcache/jit/zend_jit_x86.dasc @@ -1024,7 +1024,7 @@ static void* dasm_labels[zend_lb_MAX]; /* the same as above, but "src" may overlap with "tmp_reg1" */ |.macro ZVAL_COPY_VALUE, dst_addr, dst_info, src_addr, src_info, tmp_reg1, tmp_reg2 || if (src_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE))) { -|| if ((src_info & MAY_BE_ANY) == MAY_BE_LONG) { +|| if ((src_info & (MAY_BE_ANY|MAY_BE_GUARD)) == MAY_BE_LONG) { || if (Z_MODE(src_addr) == IS_REG) { || if (Z_MODE(dst_addr) != IS_REG || Z_REG(dst_addr) != Z_REG(src_addr)) { | SET_ZVAL_LVAL dst_addr, Ra(Z_REG(src_addr)) @@ -1035,7 +1035,7 @@ static void* dasm_labels[zend_lb_MAX]; | GET_ZVAL_LVAL tmp_reg2, src_addr | SET_ZVAL_LVAL dst_addr, Ra(tmp_reg2) || } -|| } else if ((src_info & MAY_BE_ANY) == MAY_BE_DOUBLE) { +|| } else if ((src_info & (MAY_BE_ANY|MAY_BE_GUARD)) == MAY_BE_DOUBLE) { || if (Z_MODE(src_addr) == IS_REG) { | SSE_SET_ZVAL_DVAL dst_addr, Z_REG(src_addr) || } else if (Z_MODE(dst_addr) == IS_REG) { @@ -1044,7 +1044,7 @@ static void* dasm_labels[zend_lb_MAX]; | SSE_GET_ZVAL_DVAL ZREG_XMM0, src_addr | SSE_SET_ZVAL_DVAL dst_addr, ZREG_XMM0 || } -|| } else if (!(src_info & MAY_BE_DOUBLE)) { +|| } else if (!(src_info & (MAY_BE_DOUBLE|MAY_BE_GUARD))) { | GET_ZVAL_PTR Ra(tmp_reg2), src_addr | SET_ZVAL_PTR dst_addr, Ra(tmp_reg2) || } else { @@ -1067,9 +1067,10 @@ static void* dasm_labels[zend_lb_MAX]; || } || } || if ((src_info & (MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE)) && +|| !(src_info & MAY_BE_GUARD) && || has_concrete_type(src_info & MAY_BE_ANY)) { || if (Z_MODE(dst_addr) == IS_MEM_ZVAL) { -|| if ((dst_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) != (src_info & (MAY_BE_ANY|MAY_BE_UNDEF))) { +|| if ((dst_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) != (src_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD))) { || zend_uchar type = concrete_type(src_info); | SET_ZVAL_TYPE_INFO dst_addr, type || } @@ -3558,6 +3559,13 @@ static int zend_jit_store_const(dasm_State **Dst, int var, zend_reg reg) | SET_ZVAL_W2 dst, 0x41e00000 |.endif | SET_ZVAL_TYPE_INFO dst, IS_DOUBLE + } else if (reg == ZREG_NULL) { + | SET_ZVAL_TYPE_INFO dst, IS_NULL + } else if (reg == ZREG_ZVAL_COPY_R0) { + zend_jit_addr val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_R0, 0); + + | ZVAL_COPY_VALUE dst, -1, val_addr, -1, ZREG_R1, ZREG_R2 + | TRY_ADDREF -1, ch, r2 } else { ZEND_UNREACHABLE(); } @@ -4849,6 +4857,8 @@ static int zend_jit_fetch_dimension_address_inner(dasm_State **Dst, const zend_o } } else if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && (type == BP_VAR_R || type == BP_VAR_RW)) { | jbe &exit_addr + } else if (type == BP_VAR_IS && not_found_exit_addr) { + | jbe ¬_found_exit_addr } else { | jbe >2 // NOT_FOUND } @@ -4886,6 +4896,8 @@ static int zend_jit_fetch_dimension_address_inner(dasm_State **Dst, const zend_o } } else if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && (type == BP_VAR_R || type == BP_VAR_RW)) { | jbe &exit_addr + } else if (type == BP_VAR_IS && not_found_exit_addr) { + | jbe ¬_found_exit_addr } else { | jbe >2 // NOT_FOUND } @@ -4933,12 +4945,16 @@ static int zend_jit_fetch_dimension_address_inner(dasm_State **Dst, const zend_o if (val >= 0 && val < HT_MAX_SIZE) { if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) { | jmp &exit_addr + } else if (type == BP_VAR_IS && not_found_exit_addr) { + | jmp ¬_found_exit_addr } else { | jmp >2 // NOT_FOUND } } } else if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) { | jmp &exit_addr + } else if (type == BP_VAR_IS && not_found_exit_addr) { + | jmp ¬_found_exit_addr } else { | jmp >2 // NOT_FOUND } @@ -4952,6 +4968,8 @@ static int zend_jit_fetch_dimension_address_inner(dasm_State **Dst, const zend_o | test r0, r0 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) { | jz &exit_addr + } else if (type == BP_VAR_IS && not_found_exit_addr) { + | jz ¬_found_exit_addr } else { | jz >2 // NOT_FOUND } @@ -4968,9 +4986,11 @@ static int zend_jit_fetch_dimension_address_inner(dasm_State **Dst, const zend_o break; case BP_VAR_IS: case BP_VAR_UNSET: - | // retval = &EG(uninitialized_zval); - | SET_ZVAL_TYPE_INFO res_addr, IS_NULL - | jmp >9 + if (!not_found_exit_addr) { + | // retval = &EG(uninitialized_zval); + | SET_ZVAL_TYPE_INFO res_addr, IS_NULL + | jmp >9 + } break; default: ZEND_UNREACHABLE(); @@ -5078,6 +5098,8 @@ static int zend_jit_fetch_dimension_address_inner(dasm_State **Dst, const zend_o | test r0, r0 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) { | jz &exit_addr + } else if (type == BP_VAR_IS && not_found_exit_addr) { + | jz ¬_found_exit_addr } else { | jz >2 // NOT_FOUND } @@ -5088,6 +5110,9 @@ static int zend_jit_fetch_dimension_address_inner(dasm_State **Dst, const zend_o | // retval = Z_INDIRECT_P(retval); | GET_Z_PTR r0, r0 | IF_NOT_Z_TYPE r0, IS_UNDEF, >8 + if (type == BP_VAR_IS && not_found_exit_addr) { + | jmp ¬_found_exit_addr + } |2: switch (type) { case BP_VAR_R: @@ -5101,9 +5126,11 @@ static int zend_jit_fetch_dimension_address_inner(dasm_State **Dst, const zend_o break; case BP_VAR_IS: case BP_VAR_UNSET: - | // retval = &EG(uninitialized_zval); - | SET_ZVAL_TYPE_INFO res_addr, IS_NULL - | jmp >9 + if (!not_found_exit_addr) { + | // retval = &EG(uninitialized_zval); + | SET_ZVAL_TYPE_INFO res_addr, IS_NULL + | jmp >9 + } break; default: ZEND_UNREACHABLE(); @@ -9851,6 +9878,14 @@ static int zend_jit_free_cv(dasm_State **Dst, const zend_op *opline, const zend_ return 1; } +static int zend_jit_free_op(dasm_State **Dst, const zend_op *opline, /*const zend_op_array *op_array, */uint32_t info, uint32_t var_offset) +{ + if (info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) { + | ZVAL_PTR_DTOR ZEND_ADDR_MEM_ZVAL(ZREG_FP, var_offset), info, 0, 1, opline + } + return 1; +} + static int zend_jit_leave_func(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, zend_jit_trace_rec *trace, zend_jit_trace_info *trace_info) { /* ZEND_CALL_FAKE_CLOSURE handled on slow path to eliminate check for ZEND_CALL_CLOSURE on fast path */ @@ -10203,6 +10238,8 @@ static int zend_jit_fetch_dim_read(dasm_State **Dst, const zend_op *opline, cons { zend_jit_addr orig_op1_addr, op2_addr, res_addr; const void *exit_addr = NULL; + const void *not_found_exit_addr = NULL; + const void *res_exit_addr = NULL; orig_op1_addr = OP1_ADDR(); op2_addr = OP2_ADDR(); @@ -10218,6 +10255,45 @@ static int zend_jit_fetch_dim_read(dasm_State **Dst, const zend_op *opline, cons } } + if ((res_info & MAY_BE_GUARD) + && JIT_G(current_frame) + && (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY) { + uint32_t flags = 0; + uint32_t old_info; + zend_jit_trace_stack *stack = JIT_G(current_frame)->stack; + int32_t exit_point; + + if (opline->op1_type & (IS_VAR|IS_TMP_VAR)) { + flags = ZEND_JIT_EXIT_FREE_OP1; + } + if ((opline->op2_type & (IS_VAR|IS_TMP_VAR)) + && (op2_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) { + flags = ZEND_JIT_EXIT_FREE_OP2; + } + old_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var)); + SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_UNKNOWN); + SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->result.var), ZREG_ZVAL_COPY_R0); + exit_point = zend_jit_trace_get_exit_point(opline, opline+1, NULL, flags); + SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_info); + res_exit_addr = zend_jit_trace_get_exit_addr(exit_point); + if (!res_exit_addr) { + return 0; + } + if (opline->opcode == ZEND_FETCH_DIM_IS + && !(res_info & MAY_BE_NULL)) { + old_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var)); + SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_NULL); + SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->result.var), ZREG_NULL); + exit_point = zend_jit_trace_get_exit_point(opline, opline+1, NULL, flags); + SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_info); + not_found_exit_addr = zend_jit_trace_get_exit_addr(exit_point); + if (!not_found_exit_addr) { + return 0; + } + } + res_info &= ~MAY_BE_GUARD; + } + if (op1_info & MAY_BE_REF) { | LOAD_ZVAL_ADDR FCARG1a, op1_addr | ZVAL_DEREF FCARG1a, op1_info @@ -10233,7 +10309,7 @@ static int zend_jit_fetch_dim_read(dasm_State **Dst, const zend_op *opline, cons } } | GET_ZVAL_LVAL ZREG_FCARG1a, op1_addr - if (!zend_jit_fetch_dimension_address_inner(Dst, opline, (opline->opcode != ZEND_FETCH_DIM_IS) ? BP_VAR_R : BP_VAR_IS, op1_info, op2_info, 8, 9, NULL, NULL)) { + if (!zend_jit_fetch_dimension_address_inner(Dst, opline, (opline->opcode != ZEND_FETCH_DIM_IS) ? BP_VAR_R : BP_VAR_IS, op1_info, op2_info, 8, 9, NULL, not_found_exit_addr)) { return 0; } } @@ -10365,7 +10441,17 @@ static int zend_jit_fetch_dim_read(dasm_State **Dst, const zend_op *opline, cons zend_jit_addr val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_R0, 0); |8: - if (op1_info & MAY_BE_ARRAY_OF_REF) { + if (res_exit_addr) { + zend_uchar type = concrete_type(res_info); + + if (op1_info & MAY_BE_ARRAY_OF_REF) { + | ZVAL_DEREF r0, MAY_BE_REF + } + | IF_NOT_ZVAL_TYPE val_addr, type, &res_exit_addr + | // ZVAL_COPY + | ZVAL_COPY_VALUE res_addr, -1, val_addr, res_info, ZREG_R1, ZREG_R2 + | TRY_ADDREF res_info, ch, r2 + } else if (op1_info & MAY_BE_ARRAY_OF_REF) { | // ZVAL_COPY_DEREF | GET_ZVAL_TYPE_INFO Rd(ZREG_R2), val_addr if (!zend_jit_zval_copy_deref(Dst, res_addr, val_addr, ZREG_R2)) { @@ -10373,7 +10459,7 @@ static int zend_jit_fetch_dim_read(dasm_State **Dst, const zend_op *opline, cons } } else { | // ZVAL_COPY - | ZVAL_COPY_VALUE res_addr, -1, val_addr, MAY_BE_ANY, ZREG_R1, ZREG_R2 + | ZVAL_COPY_VALUE res_addr, -1, val_addr, res_info, ZREG_R1, ZREG_R2 | TRY_ADDREF res_info, ch, r2 } } diff --git a/ext/opcache/jit/zend_jit_x86.h b/ext/opcache/jit/zend_jit_x86.h index 0ebf7a2235..10cd77a13a 100644 --- a/ext/opcache/jit/zend_jit_x86.h +++ b/ext/opcache/jit/zend_jit_x86.h @@ -71,6 +71,8 @@ typedef enum _zend_reg { ZREG_LONG_MIN, ZREG_LONG_MAX, ZREG_LONG_MAX_PLUS_1, + ZREG_NULL, + ZREG_ZVAL_COPY_R0, } zend_reg; typedef struct _zend_jit_registers_buf {