Skip to content

Commit 416d932

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 e0a8c7a commit 416d932

File tree

5 files changed

+597
-326
lines changed

5 files changed

+597
-326
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
@@ -8716,6 +8716,25 @@ ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_IS_EQUAL|ZEND_IS_IDENTICAL, (op1_info == MAY_
87168716
ZEND_VM_SMART_BRANCH(result, 0);
87178717
}
87188718

8719+
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))
8720+
{
8721+
USE_OPLINE
8722+
zval *op1, *op2;
8723+
int result;
8724+
8725+
op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
8726+
op2 = RT_CONSTANT(opline, opline->op2);
8727+
if (Z_TYPE_P(op1) == IS_STRING) {
8728+
result = zend_string_equals(Z_STR_P(op1), Z_STR_P(op2));
8729+
if (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) {
8730+
zval_ptr_dtor_str(op1);
8731+
}
8732+
} else {
8733+
result = 0;
8734+
}
8735+
ZEND_VM_SMART_BRANCH(result, 0);
8736+
}
8737+
87198738
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))
87208739
{
87218740
USE_OPLINE
@@ -8740,6 +8759,26 @@ ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_IS_NOT_EQUAL|ZEND_IS_NOT_IDENTICAL, (op1_info
87408759
ZEND_VM_SMART_BRANCH(result, 0);
87418760
}
87428761

8762+
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))
8763+
{
8764+
USE_OPLINE
8765+
zval *op1, *op2;
8766+
int result;
8767+
8768+
op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
8769+
if (Z_TYPE_P(op1) == IS_STRING) {
8770+
op2 = RT_CONSTANT(opline, opline->op2);
8771+
result = !zend_string_equals(Z_STR_P(op1), Z_STR_P(op2));
8772+
if (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) {
8773+
zval_ptr_dtor_str(op1);
8774+
}
8775+
} else {
8776+
result = 1;
8777+
}
8778+
8779+
ZEND_VM_SMART_BRANCH(result, 0);
8780+
}
8781+
87438782
ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_IS_SMALLER, (op1_info == MAY_BE_LONG && op2_info == MAY_BE_LONG), ZEND_IS_SMALLER_LONG, CONST|TMPVARCV, CONST|TMPVARCV, SPEC(SMART_BRANCH,NO_CONST_CONST))
87448783
{
87458784
USE_OPLINE

0 commit comments

Comments
 (0)