Skip to content

Commit 92705cf

Browse files
committed
Add specialized handler for checking if identical to string
This has a large performance benefit for the below snippet (0.64s vs 0.94s), and a small benefit for `$alwaysStr == 'notnumeric'`/`$s = 'other'` (for 1000 runs of test('test')) - If the literal is non-numeric and the variable is a string, `==` behaves identically to `===`, so reuse the opcode. This is similar to what was suggested in #4900 - Avoiding types with __destruct or notices simplifies the specialized implementation and avoids expensive exception handling. - TMPVARCV doesn't support FREE_OP1() - use TMPVAR|CV instead. ``` function test(string $s) : int { $total = 0; for ($i = 0; $i < 100000; $i++) { if ($s === "first") { $total++; $s = null; } } return $total; } ```
1 parent 37a7046 commit 92705cf

File tree

5 files changed

+603
-332
lines changed

5 files changed

+603
-332
lines changed

‎Zend/zend_hash.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,16 @@ static zend_always_inline int _zend_handle_numeric_str(const char *key, size_t l
349349
return _zend_handle_numeric_str_ex(key, length, idx);
350350
}
351351

352+
static zend_always_inline int zend_is_numeric_string_literal(const char *key, size_t length)
353+
{
354+
zend_ulong idx;
355+
return _zend_handle_numeric_str_ex(key, length, &idx);
356+
}
357+
358+
static zend_always_inline int zend_is_numeric_string(const zend_string *str) {
359+
return zend_is_numeric_string_literal(ZSTR_VAL(str), ZSTR_LEN(str));
360+
}
361+
352362
#define ZEND_HANDLE_NUMERIC_STR(key, length, idx) \
353363
_zend_handle_numeric_str(key, length, &idx)
354364

‎Zend/zend_vm_def.h

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8775,6 +8775,25 @@ ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_IS_EQUAL|ZEND_IS_IDENTICAL, (op1_info == MAY_
87758775
ZEND_VM_SMART_BRANCH(result, 0);
87768776
}
87778777

8778+
ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_IS_IDENTICAL|ZEND_IS_EQUAL, op->op1_type != IS_CONST && op->op2_type == IS_CONST && (op2_info == MAY_BE_STRING && (opcode == ZEND_IS_IDENTICAL ? !(op1_info & ~(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_STRING)) : (op1_info == MAY_BE_STRING && !zend_is_numeric_string(Z_STR_P(RT_CONSTANT(op, op->op2)))))), ZEND_IS_IDENTICAL_STRING, TMPVAR|CV, CONST, SPEC(COMMUTATIVE))
8779+
{
8780+
USE_OPLINE
8781+
zval *op1, *op2;
8782+
int result;
8783+
8784+
op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
8785+
op2 = RT_CONSTANT(opline, opline->op2);
8786+
if (Z_TYPE_P(op1) == IS_STRING) {
8787+
result = zend_string_equals(Z_STR_P(op1), Z_STR_P(op2));
8788+
if (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) {
8789+
zval_ptr_dtor_str(op1);
8790+
}
8791+
} else {
8792+
result = 0;
8793+
}
8794+
ZEND_VM_SMART_BRANCH(result, 0);
8795+
}
8796+
87788797
ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_IS_NOT_EQUAL|ZEND_IS_NOT_IDENTICAL, (op1_info == MAY_BE_LONG && op2_info == MAY_BE_LONG), ZEND_IS_NOT_EQUAL_LONG, CONST|TMPVARCV, CONST|TMPVARCV, SPEC(SMART_BRANCH,NO_CONST_CONST,COMMUTATIVE))
87798798
{
87808799
USE_OPLINE
@@ -8799,6 +8818,26 @@ ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_IS_NOT_EQUAL|ZEND_IS_NOT_IDENTICAL, (op1_info
87998818
ZEND_VM_SMART_BRANCH(result, 0);
88008819
}
88018820

8821+
ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_IS_NOT_IDENTICAL|ZEND_IS_NOT_EQUAL, op->op1_type != IS_CONST && op->op2_type == IS_CONST && (op2_info == MAY_BE_STRING && (opcode == ZEND_IS_NOT_IDENTICAL ? !(op1_info & ~(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_STRING)) : (op1_info == MAY_BE_STRING && !zend_is_numeric_string(Z_STR_P(RT_CONSTANT(op, op->op2)))))), ZEND_IS_NOT_IDENTICAL_STRING, TMPVAR|CV, CONST, SPEC(COMMUTATIVE))
8822+
{
8823+
USE_OPLINE
8824+
zval *op1, *op2;
8825+
int result;
8826+
8827+
op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
8828+
if (Z_TYPE_P(op1) == IS_STRING) {
8829+
op2 = RT_CONSTANT(opline, opline->op2);
8830+
result = !zend_string_equals(Z_STR_P(op1), Z_STR_P(op2));
8831+
if (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) {
8832+
zval_ptr_dtor_str(op1);
8833+
}
8834+
} else {
8835+
result = 1;
8836+
}
8837+
8838+
ZEND_VM_SMART_BRANCH(result, 0);
8839+
}
8840+
88028841
ZEND_VM_TYPE_SPEC_HANDLER(ZEND_IS_IDENTICAL, op->op1_type == IS_CV && (op->op2_type & (IS_CONST|IS_CV)) && !(op1_info & (MAY_BE_UNDEF|MAY_BE_REF)) && !(op2_info & (MAY_BE_UNDEF|MAY_BE_REF)), ZEND_IS_IDENTICAL_NOTHROW, CV, CONST|CV, SPEC(COMMUTATIVE))
88038842
{
88048843
/* This is declared below the specializations for MAY_BE_LONG/MAY_BE_DOUBLE so those will be used instead if possible. */

0 commit comments

Comments
 (0)