Skip to content

Commit 083f5f2

Browse files
committed
Improved JIT for FETCH_DIM_R/IS and ISSET_DIM_OBJ
1 parent 1003ae2 commit 083f5f2

File tree

1 file changed

+118
-99
lines changed

1 file changed

+118
-99
lines changed

ext/opcache/jit/zend_jit_x86.dasc

Lines changed: 118 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -4969,6 +4969,7 @@ static int zend_jit_fetch_dimension_address_inner(dasm_State **Dst, const zend_o
49694969

49704970
if (op2_info & MAY_BE_LONG) {
49714971
zend_bool op2_loaded = 0;
4972+
zend_bool packed_loaded = 0;
49724973

49734974
if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_LONG)) {
49744975
| // if (EXPECTED(Z_TYPE_P(dim) == IS_LONG))
@@ -4995,55 +4996,22 @@ static int zend_jit_fetch_dimension_address_inner(dasm_State **Dst, const zend_o
49954996
op2_loaded = 1;
49964997
}
49974998
if (op1_info & MAY_BE_ARRAY_PACKED) {
4999+
zend_long val = -1;
5000+
49985001
if (Z_MODE(op2_addr) == IS_CONST_ZVAL) {
4999-
zend_long val = Z_LVAL_P(Z_ZV(op2_addr));
5002+
val = Z_LVAL_P(Z_ZV(op2_addr));
50005003
if (val >= 0 && val < HT_MAX_SIZE) {
5001-
| // ZEND_HASH_INDEX_FIND(ht, hval, retval, num_undef);
5002-
if (op1_info & MAY_BE_ARRAY_HASH) {
5003-
| test dword [FCARG1a + offsetof(zend_array, u.flags)], HASH_FLAG_PACKED
5004-
| jz >4 // HASH_FIND
5005-
}
5006-
| // if (EXPECTED((zend_ulong)(_h) < (zend_ulong)(_ht)->nNumUsed))
5007-
|.if X64
5008-
| movsxd r0, dword [FCARG1a + offsetof(zend_array, nNumUsed)]
5009-
if (val == 0) {
5010-
| test r0, r0
5011-
} else {
5012-
| cmp r0, val
5013-
}
5014-
|.else
5015-
| cmp dword [FCARG1a + offsetof(zend_array, nNumUsed)], val
5016-
|.endif
5017-
if (type == BP_JIT_IS) {
5018-
if (not_found_exit_addr) {
5019-
| jbe &not_found_exit_addr
5020-
} else {
5021-
| jbe >9 // NOT_FOUND
5022-
}
5023-
} else if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) {
5024-
| jbe &exit_addr
5025-
} else if (type == BP_VAR_IS && not_found_exit_addr) {
5026-
| jbe &not_found_exit_addr
5027-
} else {
5028-
| jbe >2 // NOT_FOUND
5029-
}
5030-
| // _ret = &_ht->arData[_h].val;
5031-
| mov r0, aword [FCARG1a + offsetof(zend_array, arData)]
5032-
if (val != 0) {
5033-
| add r0, val * sizeof(Bucket)
5034-
}
5035-
if (type == BP_JIT_IS) {
5036-
| jmp >5
5037-
} else {
5038-
| IF_NOT_Z_TYPE r0, IS_UNDEF, >8
5039-
}
5004+
packed_loaded = 1;
50405005
}
50415006
} else {
50425007
if (!op2_loaded) {
50435008
| // hval = Z_LVAL_P(dim);
50445009
| GET_ZVAL_LVAL ZREG_FCARG2a, op2_addr
50455010
op2_loaded = 1;
50465011
}
5012+
packed_loaded = 1;
5013+
}
5014+
if (packed_loaded) {
50475015
| // ZEND_HASH_INDEX_FIND(ht, hval, retval, num_undef);
50485016
if (op1_info & MAY_BE_ARRAY_HASH) {
50495017
| test dword [FCARG1a + offsetof(zend_array, u.flags)], HASH_FLAG_PACKED
@@ -5052,9 +5020,19 @@ static int zend_jit_fetch_dimension_address_inner(dasm_State **Dst, const zend_o
50525020
| // if (EXPECTED((zend_ulong)(_h) < (zend_ulong)(_ht)->nNumUsed))
50535021
|.if X64
50545022
| movsxd r0, dword [FCARG1a + offsetof(zend_array, nNumUsed)]
5055-
| cmp r0, FCARG2a
5023+
if (val == 0) {
5024+
| test r0, r0
5025+
} else if (val > 0 && !op2_loaded) {
5026+
| cmp r0, val
5027+
} else {
5028+
| cmp r0, FCARG2a
5029+
}
50565030
|.else
5057-
| cmp dword [FCARG1a + offsetof(zend_array, nNumUsed)], FCARG2a
5031+
if (val >= 0 && !op2_loaded) {
5032+
| cmp dword [FCARG1a + offsetof(zend_array, nNumUsed)], val
5033+
} else {
5034+
| cmp dword [FCARG1a + offsetof(zend_array, nNumUsed)], FCARG2a
5035+
}
50585036
|.endif
50595037
if (type == BP_JIT_IS) {
50605038
if (not_found_exit_addr) {
@@ -5066,27 +5044,34 @@ static int zend_jit_fetch_dimension_address_inner(dasm_State **Dst, const zend_o
50665044
| jbe &exit_addr
50675045
} else if (type == BP_VAR_IS && not_found_exit_addr) {
50685046
| jbe &not_found_exit_addr
5047+
} else if (type == BP_VAR_IS && found_exit_addr) {
5048+
| jbe >7 // NOT_FOUND
50695049
} else {
50705050
| jbe >2 // NOT_FOUND
50715051
}
50725052
| // _ret = &_ht->arData[_h].val;
5073-
|.if X64
5074-
| mov r0, FCARG2a
5075-
| shl r0, 5
5076-
|.else
5077-
| imul r0, FCARG2a, sizeof(Bucket)
5078-
|.endif
5079-
| add r0, aword [FCARG1a + offsetof(zend_array, arData)]
5080-
if (type == BP_JIT_IS) {
5081-
| jmp >5
5053+
if (val >= 0) {
5054+
| mov r0, aword [FCARG1a + offsetof(zend_array, arData)]
5055+
if (val != 0) {
5056+
| add r0, val * sizeof(Bucket)
5057+
}
50825058
} else {
5083-
| IF_NOT_Z_TYPE r0, IS_UNDEF, >8
5059+
|.if X64
5060+
| mov r0, FCARG2a
5061+
| shl r0, 5
5062+
|.else
5063+
| imul r0, FCARG2a, sizeof(Bucket)
5064+
|.endif
5065+
| add r0, aword [FCARG1a + offsetof(zend_array, arData)]
50845066
}
50855067
}
50865068
}
50875069
switch (type) {
50885070
case BP_JIT_IS:
50895071
if (op1_info & MAY_BE_ARRAY_HASH) {
5072+
if (packed_loaded) {
5073+
| jmp >5
5074+
}
50905075
|4:
50915076
if (!op2_loaded) {
50925077
| // hval = Z_LVAL_P(dim);
@@ -5102,6 +5087,10 @@ static int zend_jit_fetch_dimension_address_inner(dasm_State **Dst, const zend_o
51025087
if (op2_info & MAY_BE_STRING) {
51035088
| jmp >5
51045089
}
5090+
} else if (packed_loaded) {
5091+
if (op2_info & MAY_BE_STRING) {
5092+
| jmp >5
5093+
}
51055094
} else if (not_found_exit_addr) {
51065095
| jmp &not_found_exit_addr
51075096
} else {
@@ -5111,14 +5100,26 @@ static int zend_jit_fetch_dimension_address_inner(dasm_State **Dst, const zend_o
51115100
case BP_VAR_R:
51125101
case BP_VAR_IS:
51135102
case BP_VAR_UNSET:
5114-
if (!(op1_info & MAY_BE_ARRAY_KEY_LONG) ||
5115-
((op1_info & MAY_BE_ARRAY_PACKED) &&
5116-
(Z_MODE(op2_addr) != IS_CONST_ZVAL ||
5117-
(Z_LVAL_P(Z_ZV(op2_addr)) >= 0 && Z_LVAL_P(Z_ZV(op2_addr)) < HT_MAX_SIZE)))) {
5103+
if (packed_loaded) {
5104+
if (op1_info & MAY_BE_ARRAY_HASH) {
5105+
| IF_NOT_Z_TYPE r0, IS_UNDEF, >8
5106+
} else if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) {
5107+
| IF_Z_TYPE r0, IS_UNDEF, &exit_addr
5108+
} else if (type == BP_VAR_IS && not_found_exit_addr) {
5109+
| IF_Z_TYPE r0, IS_UNDEF, &not_found_exit_addr
5110+
} else if (type == BP_VAR_IS && found_exit_addr) {
5111+
| IF_Z_TYPE r0, IS_UNDEF, >7 // NOT_FOUND
5112+
} else {
5113+
| IF_Z_TYPE r0, IS_UNDEF, >2 // NOT_FOUND
5114+
}
5115+
}
5116+
if (!(op1_info & MAY_BE_ARRAY_KEY_LONG) || (packed_loaded && (op1_info & MAY_BE_ARRAY_HASH))) {
51185117
if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) {
51195118
| jmp &exit_addr
51205119
} else if (type == BP_VAR_IS && not_found_exit_addr) {
51215120
| jmp &not_found_exit_addr
5121+
} else if (type == BP_VAR_IS && found_exit_addr) {
5122+
| jmp >7 // NOT_FOUND
51225123
} else {
51235124
| jmp >2 // NOT_FOUND
51245125
}
@@ -5135,6 +5136,8 @@ static int zend_jit_fetch_dimension_address_inner(dasm_State **Dst, const zend_o
51355136
| jz &exit_addr
51365137
} else if (type == BP_VAR_IS && not_found_exit_addr) {
51375138
| jz &not_found_exit_addr
5139+
} else if (type == BP_VAR_IS && found_exit_addr) {
5140+
| jz >7 // NOT_FOUND
51385141
} else {
51395142
| jz >2 // NOT_FOUND
51405143
}
@@ -5152,7 +5155,7 @@ static int zend_jit_fetch_dimension_address_inner(dasm_State **Dst, const zend_o
51525155
break;
51535156
case BP_VAR_IS:
51545157
case BP_VAR_UNSET:
5155-
if (!not_found_exit_addr) {
5158+
if (!not_found_exit_addr && !found_exit_addr) {
51565159
| // retval = &EG(uninitialized_zval);
51575160
| SET_ZVAL_TYPE_INFO res_addr, IS_NULL
51585161
| jmp >9
@@ -5164,6 +5167,9 @@ static int zend_jit_fetch_dimension_address_inner(dasm_State **Dst, const zend_o
51645167
|.code
51655168
break;
51665169
case BP_VAR_RW:
5170+
if (packed_loaded) {
5171+
| IF_NOT_Z_TYPE r0, IS_UNDEF, >8
5172+
}
51675173
|2:
51685174
|4:
51695175
if (!op2_loaded) {
@@ -5176,12 +5182,16 @@ static int zend_jit_fetch_dimension_address_inner(dasm_State **Dst, const zend_o
51765182
| jz >9
51775183
break;
51785184
case BP_VAR_W:
5179-
if (!(op1_info & MAY_BE_ARRAY_KEY_LONG) ||
5180-
((op1_info & MAY_BE_ARRAY_PACKED) &&
5181-
(Z_MODE(op2_addr) != IS_CONST_ZVAL ||
5182-
(Z_LVAL_P(Z_ZV(op2_addr)) >= 0 && Z_LVAL_P(Z_ZV(op2_addr)) < HT_MAX_SIZE)))) {
5185+
if (packed_loaded) {
5186+
| IF_NOT_Z_TYPE r0, IS_UNDEF, >8
5187+
}
5188+
if (!(op1_info & MAY_BE_ARRAY_KEY_LONG) || packed_loaded) {
51835189
|2:
51845190
| //retval = zend_hash_index_add_new(ht, hval, &EG(uninitialized_zval));
5191+
if (!op2_loaded) {
5192+
| // hval = Z_LVAL_P(dim);
5193+
| GET_ZVAL_LVAL ZREG_FCARG2a, op2_addr
5194+
}
51855195
|.if X64
51865196
| LOAD_ADDR_ZTS CARG3, executor_globals, uninitialized_zval
51875197
|.else
@@ -5198,6 +5208,10 @@ static int zend_jit_fetch_dimension_address_inner(dasm_State **Dst, const zend_o
51985208
}
51995209
if (op1_info & MAY_BE_ARRAY_HASH) {
52005210
|4:
5211+
if (!op2_loaded) {
5212+
| // hval = Z_LVAL_P(dim);
5213+
| GET_ZVAL_LVAL ZREG_FCARG2a, op2_addr
5214+
}
52015215
| EXT_CALL zend_jit_hash_index_lookup_w, r0
52025216
}
52035217
break;
@@ -5266,6 +5280,8 @@ static int zend_jit_fetch_dimension_address_inner(dasm_State **Dst, const zend_o
52665280
| jz &exit_addr
52675281
} else if (type == BP_VAR_IS && not_found_exit_addr) {
52685282
| jz &not_found_exit_addr
5283+
} else if (type == BP_VAR_IS && found_exit_addr) {
5284+
| jz >7 // NOT_FOUND
52695285
} else {
52705286
| jz >2 // NOT_FOUND
52715287
}
@@ -5286,13 +5302,11 @@ static int zend_jit_fetch_dimension_address_inner(dasm_State **Dst, const zend_o
52865302
// zend_error(E_WARNING, "Undefined array key \"%s\"", ZSTR_VAL(offset_key));
52875303
| UNDEFINED_INDEX opline
52885304
| jmp >9
5289-
} else {
5290-
| jmp &exit_addr
52915305
}
52925306
break;
52935307
case BP_VAR_IS:
52945308
case BP_VAR_UNSET:
5295-
if (!not_found_exit_addr) {
5309+
if (!not_found_exit_addr && !found_exit_addr) {
52965310
| // retval = &EG(uninitialized_zval);
52975311
| SET_ZVAL_TYPE_INFO res_addr, IS_NULL
52985312
| jmp >9
@@ -10650,7 +10664,7 @@ static int zend_jit_fetch_dim_read(dasm_State **Dst,
1065010664
}
1065110665
}
1065210666
| GET_ZVAL_LVAL ZREG_FCARG1a, op1_addr
10653-
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, NULL, not_found_exit_addr, exit_addr)) {
10667+
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, res_exit_addr, not_found_exit_addr, exit_addr)) {
1065410668
return 0;
1065510669
}
1065610670
}
@@ -10795,6 +10809,7 @@ static int zend_jit_fetch_dim_read(dasm_State **Dst,
1079510809
| IF_NOT_TYPE dl, type, &res_exit_addr
1079610810
}
1079710811
| // ZVAL_COPY
10812+
|7:
1079810813
| ZVAL_COPY_VALUE_V res_addr, -1, val_addr, res_info, ZREG_R0, ZREG_R1
1079910814
if (Z_MODE(res_addr) == IS_MEM_ZVAL) {
1080010815
if (type < IS_STRING) {
@@ -10921,7 +10936,10 @@ static int zend_jit_isset_isempty_dim(dasm_State **Dst,
1092110936
| EXT_CALL zend_jit_isset_dim_helper, r0
1092210937
| test r0, r0
1092310938
| jz >9
10924-
| jmp >8
10939+
if (op1_info & MAY_BE_ARRAY) {
10940+
| jmp >8
10941+
|.code
10942+
}
1092510943
} else {
1092610944
if (op2_info & MAY_BE_UNDEF) {
1092710945
if (op2_info & MAY_BE_ANY) {
@@ -10931,11 +10949,10 @@ static int zend_jit_isset_isempty_dim(dasm_State **Dst,
1093110949
| EXT_CALL zend_jit_undefined_op_helper, r0
1093210950
|1:
1093310951
}
10934-
| jmp >9
10935-
}
10936-
10937-
if (op1_info & MAY_BE_ARRAY) {
10938-
|.code
10952+
if (op1_info & MAY_BE_ARRAY) {
10953+
| jmp >9
10954+
|.code
10955+
}
1093910956
}
1094010957
}
1094110958

@@ -10946,40 +10963,42 @@ static int zend_jit_isset_isempty_dim(dasm_State **Dst,
1094610963
}
1094710964
#endif
1094810965

10949-
|8:
10950-
| FREE_OP opline->op2_type, opline->op2, op2_info, 0, opline
10951-
if (!op1_avoid_refcounting) {
10952-
| FREE_OP opline->op1_type, opline->op1, op1_info, 0, opline
10953-
}
10954-
if (may_throw) {
10955-
if (!zend_jit_check_exception_undef_result(Dst, opline)) {
10956-
return 0;
10966+
if (op1_info & (MAY_BE_ARRAY|MAY_BE_STRING|MAY_BE_OBJECT)) {
10967+
|8:
10968+
| FREE_OP opline->op2_type, opline->op2, op2_info, 0, opline
10969+
if (!op1_avoid_refcounting) {
10970+
| FREE_OP opline->op1_type, opline->op1, op1_info, 0, opline
1095710971
}
10958-
}
10959-
if (!(opline->extended_value & ZEND_ISEMPTY)) {
10960-
if (exit_addr) {
10961-
if (smart_branch_opcode == ZEND_JMPNZ) {
10962-
| jmp &exit_addr
10963-
} else {
10964-
| jmp >8
10972+
if (may_throw) {
10973+
if (!zend_jit_check_exception_undef_result(Dst, opline)) {
10974+
return 0;
1096510975
}
10966-
} else if (smart_branch_opcode) {
10967-
if (smart_branch_opcode == ZEND_JMPZ) {
10968-
| jmp =>target_label2
10969-
} else if (smart_branch_opcode == ZEND_JMPNZ) {
10970-
| jmp =>target_label
10971-
} else if (smart_branch_opcode == ZEND_JMPZNZ) {
10972-
| jmp =>target_label2
10976+
}
10977+
if (!(opline->extended_value & ZEND_ISEMPTY)) {
10978+
if (exit_addr) {
10979+
if (smart_branch_opcode == ZEND_JMPNZ) {
10980+
| jmp &exit_addr
10981+
} else {
10982+
| jmp >8
10983+
}
10984+
} else if (smart_branch_opcode) {
10985+
if (smart_branch_opcode == ZEND_JMPZ) {
10986+
| jmp =>target_label2
10987+
} else if (smart_branch_opcode == ZEND_JMPNZ) {
10988+
| jmp =>target_label
10989+
} else if (smart_branch_opcode == ZEND_JMPZNZ) {
10990+
| jmp =>target_label2
10991+
} else {
10992+
ZEND_UNREACHABLE();
10993+
}
1097310994
} else {
10974-
ZEND_UNREACHABLE();
10995+
| SET_ZVAL_TYPE_INFO res_addr, IS_TRUE
10996+
| jmp >8
1097510997
}
1097610998
} else {
10977-
| SET_ZVAL_TYPE_INFO res_addr, IS_TRUE
10978-
| jmp >8
10999+
| //????
11000+
| int3
1097911001
}
10980-
} else {
10981-
| //????
10982-
| int3
1098311002
}
1098411003

1098511004
|9: // not found

0 commit comments

Comments
 (0)