Skip to content

Commit c9a918b

Browse files
committed
Implement ZEND_ARRAY_KEY_EXISTS opcode to speed up array_key_exists()
1 parent 7956722 commit c9a918b

File tree

9 files changed

+1243
-534
lines changed

9 files changed

+1243
-534
lines changed

NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,8 @@ PHP NEWS
22
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
33
?? ??? ????, PHP 7.4.0alpha1
44

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

69
<<< NOTE: Insert NEWS from last stable release here prior to actual release! >>>

UPGRADING

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ PHP 7.4 UPGRADE NOTES
2323
2. New Features
2424
========================================
2525

26+
Core:
27+
. The array_key_exists() function is now optimized into a specialized
28+
ZEND_ARRAY_KEY_EXISTS instruction.
29+
2630
========================================
2731
3. Changes in SAPI modules
2832
========================================

Zend/zend_compile.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2194,6 +2194,7 @@ ZEND_API int zend_is_smart_branch(zend_op *opline) /* {{{ */
21942194
case ZEND_TYPE_CHECK:
21952195
case ZEND_DEFINED:
21962196
case ZEND_IN_ARRAY:
2197+
case ZEND_ARRAY_KEY_EXISTS:
21972198
return 1;
21982199
default:
21992200
return 0;
@@ -3862,6 +3863,22 @@ int zend_compile_func_get_args(znode *result, zend_ast_list *args) /* {{{ */
38623863
}
38633864
/* }}} */
38643865

3866+
int zend_compile_func_array_key_exists(znode *result, zend_ast_list *args) /* {{{ */
3867+
{
3868+
if (args->children != 2 || args->child[0]->kind == ZEND_AST_UNPACK) {
3869+
return FAILURE;
3870+
}
3871+
3872+
znode subject, needle;
3873+
3874+
zend_compile_expr(&needle, args->child[0]);
3875+
zend_compile_expr(&subject, args->child[1]);
3876+
3877+
zend_emit_op_tmp(result, ZEND_ARRAY_KEY_EXISTS, &needle, &subject);
3878+
return SUCCESS;
3879+
}
3880+
/* }}} */
3881+
38653882
int zend_compile_func_array_slice(znode *result, zend_ast_list *args) /* {{{ */
38663883
{
38673884
if (CG(active_op_array)->function_name
@@ -3969,6 +3986,8 @@ int zend_try_compile_special_func(znode *result, zend_string *lcname, zend_ast_l
39693986
return zend_compile_func_get_args(result, args);
39703987
} else if (zend_string_equals_literal(lcname, "array_slice")) {
39713988
return zend_compile_func_array_slice(result, args);
3989+
} else if (zend_string_equals_literal(lcname, "array_key_exists")) {
3990+
return zend_compile_func_array_key_exists(result, args);
39723991
} else {
39733992
return FAILURE;
39743993
}

Zend/zend_vm_def.h

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6405,6 +6405,64 @@ ZEND_VM_C_LABEL(isset_no_object):
64056405
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
64066406
}
64076407

6408+
ZEND_VM_HANDLER(199, ZEND_ARRAY_KEY_EXISTS, CV|TMPVAR|CONST, CV|TMPVAR|CONST)
6409+
{
6410+
USE_OPLINE
6411+
6412+
zend_free_op free_op1, free_op2;
6413+
zval *key, *subject;
6414+
HashTable* ht;
6415+
int result;
6416+
6417+
SAVE_OPLINE();
6418+
6419+
key = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
6420+
subject = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R);
6421+
6422+
ZEND_VM_C_LABEL(try_again_subject):
6423+
if (EXPECTED(Z_TYPE_P(subject) == IS_ARRAY)) {
6424+
ht = Z_ARRVAL_P(subject);
6425+
} else if (UNEXPECTED(Z_TYPE_P(subject) == IS_OBJECT)) {
6426+
ht = Z_OBJPROP_P(subject);
6427+
} else if (Z_ISREF_P(subject)) {
6428+
subject = Z_REFVAL_P(subject);
6429+
ZEND_VM_C_GOTO(try_again_subject);
6430+
} else {
6431+
if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(key) == IS_UNDEF)) {
6432+
key = GET_OP1_UNDEF_CV(key, BP_VAR_R);
6433+
}
6434+
if (OP2_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(subject) == IS_UNDEF)) {
6435+
subject = GET_OP2_UNDEF_CV(subject, BP_VAR_R);
6436+
}
6437+
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)));
6438+
FREE_OP2();
6439+
FREE_OP1();
6440+
ZVAL_NULL(EX_VAR(opline->result.var));
6441+
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
6442+
}
6443+
6444+
ZEND_VM_C_LABEL(try_again_key):
6445+
if (EXPECTED(Z_TYPE_P(key) == IS_STRING)) {
6446+
result = zend_symtable_exists_ind(ht, Z_STR_P(key));
6447+
} else if (EXPECTED(Z_TYPE_P(key) == IS_LONG)) {
6448+
result = zend_hash_index_exists(ht, Z_LVAL_P(key));
6449+
} else if (UNEXPECTED(Z_TYPE_P(key) == IS_NULL)) {
6450+
result = zend_symtable_exists_ind(ht, ZSTR_EMPTY_ALLOC());
6451+
} else if (Z_ISREF_P(key)) {
6452+
key = Z_REFVAL_P(key);
6453+
ZEND_VM_C_GOTO(try_again_key);
6454+
} else {
6455+
zend_error(E_WARNING, "array_key_exists(): The first argument should be either a string or an integer");
6456+
result = 0;
6457+
}
6458+
6459+
FREE_OP2();
6460+
FREE_OP1();
6461+
ZEND_VM_SMART_BRANCH(result, 1);
6462+
ZVAL_BOOL(EX_VAR(opline->result.var), result);
6463+
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
6464+
}
6465+
64086466
ZEND_VM_COLD_HANDLER(79, ZEND_EXIT, CONST|TMPVAR|UNUSED|CV, ANY)
64096467
{
64106468
USE_OPLINE

0 commit comments

Comments
 (0)