Skip to content

Commit

Permalink
Implement ZEND_ARRAY_KEY_EXISTS opcode to speed up array_key_exists()
Browse files Browse the repository at this point in the history
  • Loading branch information
Majkl578 committed Aug 14, 2018
1 parent 7956722 commit c9a918b
Show file tree
Hide file tree
Showing 9 changed files with 1,243 additions and 534 deletions.
3 changes: 3 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,8 @@ PHP NEWS
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
?? ??? ????, PHP 7.4.0alpha1

- Core:
. Implemented request #76148 (Add array_key_exists() to the list of
specially compiled functions). (Majkl578)

<<< NOTE: Insert NEWS from last stable release here prior to actual release! >>>
4 changes: 4 additions & 0 deletions UPGRADING
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ PHP 7.4 UPGRADE NOTES
2. New Features
========================================

Core:
. The array_key_exists() function is now optimized into a specialized
ZEND_ARRAY_KEY_EXISTS instruction.

========================================
3. Changes in SAPI modules
========================================
Expand Down
19 changes: 19 additions & 0 deletions Zend/zend_compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -2194,6 +2194,7 @@ ZEND_API int zend_is_smart_branch(zend_op *opline) /* {{{ */
case ZEND_TYPE_CHECK:
case ZEND_DEFINED:
case ZEND_IN_ARRAY:
case ZEND_ARRAY_KEY_EXISTS:
return 1;
default:
return 0;
Expand Down Expand Up @@ -3862,6 +3863,22 @@ int zend_compile_func_get_args(znode *result, zend_ast_list *args) /* {{{ */
}
/* }}} */

int zend_compile_func_array_key_exists(znode *result, zend_ast_list *args) /* {{{ */
{
if (args->children != 2 || args->child[0]->kind == ZEND_AST_UNPACK) {
return FAILURE;
}

znode subject, needle;

zend_compile_expr(&needle, args->child[0]);
zend_compile_expr(&subject, args->child[1]);

zend_emit_op_tmp(result, ZEND_ARRAY_KEY_EXISTS, &needle, &subject);
return SUCCESS;
}
/* }}} */

int zend_compile_func_array_slice(znode *result, zend_ast_list *args) /* {{{ */
{
if (CG(active_op_array)->function_name
Expand Down Expand Up @@ -3969,6 +3986,8 @@ int zend_try_compile_special_func(znode *result, zend_string *lcname, zend_ast_l
return zend_compile_func_get_args(result, args);
} else if (zend_string_equals_literal(lcname, "array_slice")) {
return zend_compile_func_array_slice(result, args);
} else if (zend_string_equals_literal(lcname, "array_key_exists")) {
return zend_compile_func_array_key_exists(result, args);
} else {
return FAILURE;
}
Expand Down
58 changes: 58 additions & 0 deletions Zend/zend_vm_def.h
Original file line number Diff line number Diff line change
Expand Up @@ -6405,6 +6405,64 @@ ZEND_VM_C_LABEL(isset_no_object):
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}

ZEND_VM_HANDLER(199, ZEND_ARRAY_KEY_EXISTS, CV|TMPVAR|CONST, CV|TMPVAR|CONST)
{
USE_OPLINE

zend_free_op free_op1, free_op2;
zval *key, *subject;
HashTable* ht;
int result;

SAVE_OPLINE();

key = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
subject = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R);

ZEND_VM_C_LABEL(try_again_subject):
if (EXPECTED(Z_TYPE_P(subject) == IS_ARRAY)) {
ht = Z_ARRVAL_P(subject);
} else if (UNEXPECTED(Z_TYPE_P(subject) == IS_OBJECT)) {
ht = Z_OBJPROP_P(subject);
} else if (Z_ISREF_P(subject)) {
subject = Z_REFVAL_P(subject);
ZEND_VM_C_GOTO(try_again_subject);
} else {
if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(key) == IS_UNDEF)) {
key = GET_OP1_UNDEF_CV(key, BP_VAR_R);
}
if (OP2_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(subject) == IS_UNDEF)) {
subject = GET_OP2_UNDEF_CV(subject, BP_VAR_R);
}
zend_internal_type_error(EX_USES_STRICT_TYPES(), "array_key_exists() expects parameter 2 to be array, %s given", zend_get_type_by_const(Z_TYPE_P(subject)));
FREE_OP2();
FREE_OP1();
ZVAL_NULL(EX_VAR(opline->result.var));
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}

ZEND_VM_C_LABEL(try_again_key):
if (EXPECTED(Z_TYPE_P(key) == IS_STRING)) {
result = zend_symtable_exists_ind(ht, Z_STR_P(key));
} else if (EXPECTED(Z_TYPE_P(key) == IS_LONG)) {
result = zend_hash_index_exists(ht, Z_LVAL_P(key));
} else if (UNEXPECTED(Z_TYPE_P(key) == IS_NULL)) {
result = zend_symtable_exists_ind(ht, ZSTR_EMPTY_ALLOC());
} else if (Z_ISREF_P(key)) {
key = Z_REFVAL_P(key);
ZEND_VM_C_GOTO(try_again_key);
} else {
zend_error(E_WARNING, "array_key_exists(): The first argument should be either a string or an integer");
result = 0;
}

FREE_OP2();
FREE_OP1();
ZEND_VM_SMART_BRANCH(result, 1);
ZVAL_BOOL(EX_VAR(opline->result.var), result);
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}

ZEND_VM_COLD_HANDLER(79, ZEND_EXIT, CONST|TMPVAR|UNUSED|CV, ANY)
{
USE_OPLINE
Expand Down
Loading

0 comments on commit c9a918b

Please sign in to comment.