Skip to content

Commit

Permalink
Add specialized handler for checking if identical to string
Browse files Browse the repository at this point in the history
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 php#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;
}
```
  • Loading branch information
TysonAndre committed Aug 9, 2020
1 parent 05478e9 commit e6f8df2
Show file tree
Hide file tree
Showing 5 changed files with 603 additions and 332 deletions.
10 changes: 10 additions & 0 deletions Zend/zend_hash.h
Expand Up @@ -371,6 +371,16 @@ static zend_always_inline int _zend_handle_numeric_str(const char *key, size_t l
return _zend_handle_numeric_str_ex(key, length, idx);
}

static zend_always_inline int zend_is_numeric_string_literal(const char *key, size_t length)
{
zend_ulong idx;
return _zend_handle_numeric_str_ex(key, length, &idx);
}

static zend_always_inline int zend_is_numeric_string(const zend_string *str) {
return zend_is_numeric_string_literal(ZSTR_VAL(str), ZSTR_LEN(str));
}

#define ZEND_HANDLE_NUMERIC_STR(key, length, idx) \
_zend_handle_numeric_str(key, length, &idx)

Expand Down
39 changes: 39 additions & 0 deletions Zend/zend_vm_def.h
Expand Up @@ -9190,6 +9190,25 @@ ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_IS_EQUAL|ZEND_IS_IDENTICAL, (op1_info == MAY_
ZEND_VM_SMART_BRANCH(result, 0);
}

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))
{
USE_OPLINE
zval *op1, *op2;
int result;

op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
op2 = RT_CONSTANT(opline, opline->op2);
if (Z_TYPE_P(op1) == IS_STRING) {
result = zend_string_equals(Z_STR_P(op1), Z_STR_P(op2));
if (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) {
zval_ptr_dtor_str(op1);
}
} else {
result = 0;
}
ZEND_VM_SMART_BRANCH(result, 0);
}

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))
{
USE_OPLINE
Expand All @@ -9214,6 +9233,26 @@ ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_IS_NOT_EQUAL|ZEND_IS_NOT_IDENTICAL, (op1_info
ZEND_VM_SMART_BRANCH(result, 0);
}

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))
{
USE_OPLINE
zval *op1, *op2;
int result;

op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
if (Z_TYPE_P(op1) == IS_STRING) {
op2 = RT_CONSTANT(opline, opline->op2);
result = !zend_string_equals(Z_STR_P(op1), Z_STR_P(op2));
if (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) {
zval_ptr_dtor_str(op1);
}
} else {
result = 1;
}

ZEND_VM_SMART_BRANCH(result, 0);
}

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))
{
/* This is declared below the specializations for MAY_BE_LONG/MAY_BE_DOUBLE so those will be used instead if possible. */
Expand Down

0 comments on commit e6f8df2

Please sign in to comment.