Skip to content

Commit 12cdab2

Browse files
committed
Improved JIT for BIND_GLOBAL
1 parent df79277 commit 12cdab2

File tree

5 files changed

+98
-156
lines changed

5 files changed

+98
-156
lines changed

Zend/zend_vm_def.h

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7855,23 +7855,22 @@ ZEND_VM_C_LABEL(check_indirect):
78557855
variable_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_W);
78567856

78577857
if (UNEXPECTED(Z_REFCOUNTED_P(variable_ptr))) {
7858-
zend_refcounted *ref = Z_COUNTED_P(variable_ptr);
7859-
uint32_t refcnt = GC_DELREF(ref);
7858+
zend_refcounted *garbage = Z_COUNTED_P(variable_ptr);
78607859

7861-
if (EXPECTED(variable_ptr != value)) {
7862-
if (refcnt == 0) {
7863-
SAVE_OPLINE();
7864-
rc_dtor_func(ref);
7865-
if (UNEXPECTED(EG(exception))) {
7866-
ZVAL_NULL(variable_ptr);
7867-
HANDLE_EXCEPTION();
7868-
}
7869-
} else {
7870-
gc_check_possible_root(ref);
7860+
ZVAL_REF(variable_ptr, ref);
7861+
if (GC_DELREF(garbage) == 0) {
7862+
SAVE_OPLINE();
7863+
rc_dtor_func(garbage);
7864+
if (UNEXPECTED(EG(exception))) {
7865+
ZVAL_NULL(variable_ptr);
7866+
HANDLE_EXCEPTION();
78717867
}
7868+
} else {
7869+
gc_check_possible_root(garbage);
78727870
}
7871+
} else {
7872+
ZVAL_REF(variable_ptr, ref);
78737873
}
7874-
ZVAL_REF(variable_ptr, ref);
78757874

78767875
ZEND_VM_REPEAT_OPCODE(ZEND_BIND_GLOBAL);
78777876
ZEND_VM_NEXT_OPCODE();

Zend/zend_vm_execute.h

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -40324,23 +40324,22 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_BIND_GLOBAL_SPEC_C
4032440324
variable_ptr = EX_VAR(opline->op1.var);
4032540325

4032640326
if (UNEXPECTED(Z_REFCOUNTED_P(variable_ptr))) {
40327-
zend_refcounted *ref = Z_COUNTED_P(variable_ptr);
40328-
uint32_t refcnt = GC_DELREF(ref);
40327+
zend_refcounted *garbage = Z_COUNTED_P(variable_ptr);
4032940328

40330-
if (EXPECTED(variable_ptr != value)) {
40331-
if (refcnt == 0) {
40332-
SAVE_OPLINE();
40333-
rc_dtor_func(ref);
40334-
if (UNEXPECTED(EG(exception))) {
40335-
ZVAL_NULL(variable_ptr);
40336-
HANDLE_EXCEPTION();
40337-
}
40338-
} else {
40339-
gc_check_possible_root(ref);
40329+
ZVAL_REF(variable_ptr, ref);
40330+
if (GC_DELREF(garbage) == 0) {
40331+
SAVE_OPLINE();
40332+
rc_dtor_func(garbage);
40333+
if (UNEXPECTED(EG(exception))) {
40334+
ZVAL_NULL(variable_ptr);
40335+
HANDLE_EXCEPTION();
4034040336
}
40337+
} else {
40338+
gc_check_possible_root(garbage);
4034140339
}
40340+
} else {
40341+
ZVAL_REF(variable_ptr, ref);
4034240342
}
40343-
ZVAL_REF(variable_ptr, ref);
4034440343

4034540344
ZEND_VM_REPEAT_OPCODE(ZEND_BIND_GLOBAL);
4034640345
ZEND_VM_NEXT_OPCODE();

ext/opcache/jit/zend_jit_disasm_x86.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -427,7 +427,6 @@ static int zend_jit_disasm_init(void)
427427
REGISTER_HELPER(zend_jit_isset_dim_helper);
428428
REGISTER_HELPER(zend_jit_free_call_frame);
429429
REGISTER_HELPER(zend_jit_zval_copy_deref_helper)
430-
REGISTER_HELPER(zend_jit_new_ref_helper);
431430
REGISTER_HELPER(zend_jit_fetch_global_helper);
432431
REGISTER_HELPER(zend_jit_verify_arg_slow);
433432
REGISTER_HELPER(zend_jit_fetch_obj_r_slow);

ext/opcache/jit/zend_jit_helpers.c

Lines changed: 31 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1098,33 +1098,39 @@ static void ZEND_FASTCALL zend_jit_free_call_frame(zend_execute_data *call)
10981098
zend_vm_stack_free_call_frame(call);
10991099
}
11001100

1101-
static zval* ZEND_FASTCALL zend_jit_new_ref_helper(zval *value)
1101+
static zend_reference* ZEND_FASTCALL zend_jit_fetch_global_helper(zend_string *varname, void **cache_slot)
11021102
{
1103-
zend_reference *ref = (zend_reference*)emalloc(sizeof(zend_reference));
1104-
GC_SET_REFCOUNT(ref, 1);
1105-
GC_TYPE_INFO(ref) = IS_REFERENCE;
1106-
ref->sources.ptr = NULL;
1107-
ZVAL_COPY_VALUE(&ref->val, value);
1108-
Z_REF_P(value) = ref;
1109-
Z_TYPE_INFO_P(value) = IS_REFERENCE_EX;
1110-
1111-
return value;
1112-
}
1113-
1114-
static zval* ZEND_FASTCALL zend_jit_fetch_global_helper(zend_execute_data *execute_data, zval *varname, uint32_t cache_slot)
1115-
{
1116-
uint32_t idx;
1117-
zval *value = zend_hash_find(&EG(symbol_table), Z_STR_P(varname));
1103+
zval *value;
1104+
uintptr_t idx;
1105+
zend_reference *ref;
1106+
1107+
/* We store "hash slot index" + 1 (NULL is a mark of uninitialized cache slot) */
1108+
idx = (uintptr_t)CACHED_PTR_EX(cache_slot) - 1;
1109+
if (EXPECTED(idx < EG(symbol_table).nNumUsed * sizeof(Bucket))) {
1110+
Bucket *p = (Bucket*)((char*)EG(symbol_table).arData + idx);
1111+
1112+
if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF) &&
1113+
(EXPECTED(p->key == varname) ||
1114+
(EXPECTED(p->h == ZSTR_H(varname)) &&
1115+
EXPECTED(p->key != NULL) &&
1116+
EXPECTED(zend_string_equal_content(p->key, varname))))) {
1117+
1118+
value = (zval*)p; /* value = &p->val; */
1119+
goto check_indirect;
1120+
}
1121+
}
11181122

1123+
value = zend_hash_find_ex(&EG(symbol_table), varname, 1);
11191124
if (UNEXPECTED(value == NULL)) {
1120-
value = zend_hash_add_new(&EG(symbol_table), Z_STR_P(varname), &EG(uninitialized_zval));
1125+
value = zend_hash_add_new(&EG(symbol_table), varname, &EG(uninitialized_zval));
11211126
idx = (char*)value - (char*)EG(symbol_table).arData;
11221127
/* Store "hash slot index" + 1 (NULL is a mark of uninitialized cache slot) */
1123-
CACHE_PTR(cache_slot, (void*)(uintptr_t)(idx + 1));
1128+
CACHE_PTR_EX(cache_slot, (void*)(idx + 1));
11241129
} else {
11251130
idx = (char*)value - (char*)EG(symbol_table).arData;
11261131
/* Store "hash slot index" + 1 (NULL is a mark of uninitialized cache slot) */
1127-
CACHE_PTR(cache_slot, (void*)(uintptr_t)(idx + 1));
1132+
CACHE_PTR_EX(cache_slot, (void*)(idx + 1));
1133+
check_indirect:
11281134
/* GLOBAL variable may be an INDIRECT pointer to CV */
11291135
if (UNEXPECTED(Z_TYPE_P(value) == IS_INDIRECT)) {
11301136
value = Z_INDIRECT_P(value);
@@ -1135,10 +1141,14 @@ static zval* ZEND_FASTCALL zend_jit_fetch_global_helper(zend_execute_data *execu
11351141
}
11361142

11371143
if (UNEXPECTED(!Z_ISREF_P(value))) {
1138-
return zend_jit_new_ref_helper(value);
1144+
ZVAL_MAKE_REF_EX(value, 2);
1145+
ref = Z_REF_P(value);
1146+
} else {
1147+
ref = Z_REF_P(value);
1148+
GC_ADDREF(ref);
11391149
}
11401150

1141-
return value;
1151+
return ref;
11421152
}
11431153

11441154
static zend_always_inline zend_bool zend_jit_verify_type_common(zval *arg, const zend_op_array *op_array, zend_arg_info *arg_info, void **cache_slot)

ext/opcache/jit/zend_jit_x86.dasc

Lines changed: 43 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -9767,13 +9767,13 @@ static int zend_jit_isset_isempty_dim(dasm_State **Dst, const zend_op *opline, c
97679767
static int zend_jit_bind_global(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, uint32_t op1_info)
97689768
{
97699769
zend_jit_addr op1_addr = OP1_ADDR();
9770-
zval *varname = RT_CONSTANT(opline, opline->op2);
9770+
zend_string *varname = Z_STR_P(RT_CONSTANT(opline, opline->op2));
97719771

9772-
//idx = (uint32_t)(uintptr_t)CACHED_PTR(opline->extended_value) - 1;
9772+
| // idx = (uint32_t)(uintptr_t)CACHED_PTR(opline->extended_value) - 1;
97739773
| mov r0, EX->run_time_cache
97749774
| mov r0, aword [r0 + opline->extended_value]
97759775
| sub r0, 1
9776-
//if (EXPECTED(idx < EG(symbol_table).nNumUsed * sizeof(Bucket)))
9776+
| // if (EXPECTED(idx < EG(symbol_table).nNumUsed * sizeof(Bucket)))
97779777
|.if X64
97789778
| MEM_OP2_2_ZTS movsxd, r1, dword, executor_globals, symbol_table.nNumUsed, r1
97799779
| shl r1, 5
@@ -9783,129 +9783,64 @@ static int zend_jit_bind_global(dasm_State **Dst, const zend_op *opline, const z
97839783
|.endif
97849784
| cmp r0, r1
97859785
| jae >9
9786-
//Bucket *p = (Bucket*)((char*)EG(symbol_table).arData + idx);
9786+
| // Bucket *p = (Bucket*)((char*)EG(symbol_table).arData + idx);
97879787
| MEM_OP2_2_ZTS add, r0, aword, executor_globals, symbol_table.arData, r1
9788-
| IF_Z_TYPE r0, IS_UNDEF, >9
9789-
// (EXPECTED(p->key == Z_STR_P(varname))
9790-
| ADDR_OP2_2 cmp, aword [r0 + offsetof(Bucket, key)], Z_PTR_P(varname), r1
9791-
| jne >1
9792-
|.cold_code
9793-
|1:
9794-
//(EXPECTED(p->h == ZSTR_H(Z_STR_P(varname)))
9795-
| ADDR_OP2_2 cmp, aword [r0 + offsetof(Bucket, h)], ZSTR_H(Z_STR_P(varname)), r1
9788+
| IF_NOT_Z_TYPE r0, IS_REFERENCE, >9
9789+
| // (EXPECTED(p->key == varname))
9790+
| ADDR_OP2_2 cmp, aword [r0 + offsetof(Bucket, key)], varname, r1
97969791
| jne >9
9797-
//EXPECTED(p->key != NULL)
9798-
| mov r1, [r0 + offsetof(Bucket, key)]
9799-
| test r1, r1
9800-
| jz >9
9801-
//EXPECTED(ZSTR_LEN(p->key) == Z_STRLEN_P(varname))
9802-
| ADDR_OP2_2 cmp, aword [r1 + offsetof(zend_string, len)], Z_STRLEN_P(varname), r2
9803-
| jne >9
9804-
//EXPECTED(memcmp(ZSTR_VAL(p->key), Z_STRVAL_P(varname), Z_STRLEN_P(varname)) == 0)
9805-
| add r1, offsetof(zend_string, val)
9806-
| mov T1, r0
9807-
|.if X64
9808-
| mov CARG1, r1
9809-
| LOAD_ADDR CARG2, Z_STRVAL_P(varname)
9810-
| mov CARG3, Z_STRLEN_P(varname)
9811-
| EXT_CALL memcmp, r0
9812-
|.else
9813-
| sub r4, 4
9814-
| push Z_STRLEN_P(varname)
9815-
| push Z_STRVAL_P(varname)
9816-
| push r1
9817-
| call &memcmp
9818-
| add r4, 16
9819-
|.endif
9820-
| test al, al
9821-
| mov r0, aword T1
9822-
| jnz >9
9823-
| jmp >2
9824-
|.code
9825-
|2:
9826-
// if (UNEXPECTED(Z_TYPE_P(value) == IS_INDIRECT))
9827-
| mov cl, byte [r0 + 8]
9828-
| cmp cl, IS_INDIRECT
9829-
| je >1
9830-
|.cold_code
9831-
|1:
9832-
//value = Z_INDIRECT_P(value)
9833-
| mov r0, [r0]
9834-
| mov cl, byte [r0 + 8]
9835-
| test cl, cl // cmp cl, IS_UNDEF
9836-
| jne >2
9837-
| SET_Z_TYPE_INFO r0, IS_NULL
9838-
|.code
9839-
|2:
9840-
| cmp cl, IS_REFERENCE
9841-
| jne >8
9842-
|1:
9843-
if (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) {
9844-
//stash this for later use
9845-
| mov r2, r0
9846-
}
98479792
| GET_Z_PTR r0, r0
98489793
| GC_ADDREF r0
9849-
//if (UNEXPECTED(Z_REFCOUNTED_P(variable_ptr)))
9794+
|1:
98509795
if (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) {
9851-
if (op1_info & (MAY_BE_ANY - (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
9852-
| IF_ZVAL_REFCOUNTED op1_addr, >2
9796+
if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
9797+
| // if (UNEXPECTED(Z_REFCOUNTED_P(variable_ptr)))
9798+
| IF_ZVAL_REFCOUNTED op1_addr, >2
9799+
|.cold_code
9800+
|2:
98539801
}
9854-
|.cold_code
9855-
//zval_dtor_func(Z_COUNTED_P(variable_ptr))
9856-
|2:
9857-
//if (EXPECTED(variable_ptr != value))
9858-
| LOAD_ZVAL_ADDR FCARG1a, op1_addr
9859-
| cmp FCARG1a, r2
9860-
| je >4
9861-
| GET_Z_PTR FCARG1a, FCARG1a
9802+
| // zend_refcounted *garbage = Z_COUNTED_P(variable_ptr);
9803+
| GET_ZVAL_PTR FCARG1a, op1_addr
9804+
| // ZVAL_REF(variable_ptr, ref)
9805+
| SET_ZVAL_PTR op1_addr, r0
9806+
| SET_ZVAL_TYPE_INFO op1_addr, IS_REFERENCE_EX
9807+
| // if (GC_DELREF(garbage) == 0)
98629808
| GC_DELREF FCARG1a
9863-
if (op1_info & (MAY_BE_ARRAY|MAY_BE_OBJECT)) {
9864-
| jnz >3
9809+
if (op1_info & (MAY_BE_REF|MAY_BE_ARRAY|MAY_BE_OBJECT)) {
9810+
| jnz >3
9811+
} else {
9812+
| jnz >5
98659813
}
9866-
| mov aword T1, r0 // save
98679814
| ZVAL_DTOR_FUNC op1_info, opline
9868-
| mov r0, aword T1 // restore
9869-
| jmp >5
9870-
if (op1_info & (MAY_BE_ARRAY|MAY_BE_OBJECT)) {
9871-
|3:
9872-
// GC_ZVAL_CHECK_POSSIBLE_ROOT(variable_ptr)
9873-
| IF_GC_MAY_NOT_LEAK FCARG1a, edx, >5
9874-
| mov aword T1, r0 //save
9875-
| EXT_CALL gc_possible_root, r1
9876-
| mov r0, aword T1 // restore
98779815
| jmp >5
9816+
if (op1_info & (MAY_BE_REF|MAY_BE_ARRAY|MAY_BE_OBJECT)) {
9817+
|3:
9818+
| // GC_ZVAL_CHECK_POSSIBLE_ROOT(variable_ptr)
9819+
| IF_GC_MAY_NOT_LEAK FCARG1a, edx, >5
9820+
| EXT_CALL gc_possible_root, r1
9821+
| jmp >5
9822+
}
9823+
if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
9824+
|.code
98789825
}
9879-
|4:
9880-
| GET_Z_PTR FCARG1a, FCARG1a
9881-
| GC_DELREF FCARG1a
9882-
| jmp >5
9883-
|.code
9826+
}
9827+
9828+
if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
9829+
| // ZVAL_REF(variable_ptr, ref)
9830+
| SET_ZVAL_PTR op1_addr, r0
9831+
| SET_ZVAL_TYPE_INFO op1_addr, IS_REFERENCE_EX
98849832
}
98859833
|5:
9886-
//ZVAL_REF(variable_ptr, ref)
9887-
| SET_ZVAL_PTR op1_addr, r0
9888-
| SET_ZVAL_TYPE_INFO op1_addr, IS_REFERENCE_EX
98899834
//END of handler
98909835

98919836
|.cold_code
9892-
|8:
9893-
| mov FCARG1a, r0
9894-
| EXT_CALL zend_jit_new_ref_helper, r0
9895-
| jmp <1
98969837
|9:
9897-
| mov FCARG1a, FP
9898-
| LOAD_ADDR FCARG2a, (ptrdiff_t)varname
9899-
|.if X64
9900-
| mov CARG3, opline->extended_value
9901-
|.else
9902-
| sub r4, 12
9903-
| push opline->extended_value
9904-
|.endif
9838+
| LOAD_ADDR FCARG1a, (ptrdiff_t)varname
9839+
| mov FCARG2a, EX->run_time_cache
9840+
if (opline->extended_value) {
9841+
| add FCARG2a, opline->extended_value
9842+
}
99059843
| EXT_CALL zend_jit_fetch_global_helper, r0
9906-
|.if not(X64)
9907-
| add r4, 12
9908-
|.endif
99099844
| jmp <1
99109845
|.code
99119846

0 commit comments

Comments
 (0)