Skip to content

Commit e6f8df2

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 05478e9 commit e6f8df2

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
@@ -371,6 +371,16 @@ static zend_always_inline int _zend_handle_numeric_str(const char *key, size_t l
371371
return _zend_handle_numeric_str_ex(key, length, idx);
372372
}
373373

374+
static zend_always_inline int zend_is_numeric_string_literal(const char *key, size_t length)
375+
{
376+
zend_ulong idx;
377+
return _zend_handle_numeric_str_ex(key, length, &idx);
378+
}
379+
380+
static zend_always_inline int zend_is_numeric_string(const zend_string *str) {
381+
return zend_is_numeric_string_literal(ZSTR_VAL(str), ZSTR_LEN(str));
382+
}
383+
374384
#define ZEND_HANDLE_NUMERIC_STR(key, length, idx) \
375385
_zend_handle_numeric_str(key, length, &idx)
376386

Zend/zend_vm_def.h

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

9193+
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))
9194+
{
9195+
USE_OPLINE
9196+
zval *op1, *op2;
9197+
int result;
9198+
9199+
op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
9200+
op2 = RT_CONSTANT(opline, opline->op2);
9201+
if (Z_TYPE_P(op1) == IS_STRING) {
9202+
result = zend_string_equals(Z_STR_P(op1), Z_STR_P(op2));
9203+
if (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) {
9204+
zval_ptr_dtor_str(op1);
9205+
}
9206+
} else {
9207+
result = 0;
9208+
}
9209+
ZEND_VM_SMART_BRANCH(result, 0);
9210+
}
9211+
91939212
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))
91949213
{
91959214
USE_OPLINE
@@ -9214,6 +9233,26 @@ ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_IS_NOT_EQUAL|ZEND_IS_NOT_IDENTICAL, (op1_info
92149233
ZEND_VM_SMART_BRANCH(result, 0);
92159234
}
92169235

9236+
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))
9237+
{
9238+
USE_OPLINE
9239+
zval *op1, *op2;
9240+
int result;
9241+
9242+
op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
9243+
if (Z_TYPE_P(op1) == IS_STRING) {
9244+
op2 = RT_CONSTANT(opline, opline->op2);
9245+
result = !zend_string_equals(Z_STR_P(op1), Z_STR_P(op2));
9246+
if (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) {
9247+
zval_ptr_dtor_str(op1);
9248+
}
9249+
} else {
9250+
result = 1;
9251+
}
9252+
9253+
ZEND_VM_SMART_BRANCH(result, 0);
9254+
}
9255+
92179256
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))
92189257
{
92199258
/* 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)