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 authored and dstogov committed Dec 26, 2018
1 parent 9bd4aab commit f5044a1
Show file tree
Hide file tree
Showing 8 changed files with 1,298 additions and 538 deletions.
4 changes: 4 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ PHP NEWS
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
?? ??? ????, PHP 7.4.0alpha1

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

- CURL:
. Fixed bug #76480 (Use curl_multi_wait() so that timeouts are respected).
(Pierrick)
Expand Down
19 changes: 19 additions & 0 deletions Zend/zend_compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -2088,6 +2088,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 @@ -3758,6 +3759,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) /* {{{ */
{
znode subject, needle;

if (args->children != 2) {
return FAILURE;
}

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 @@ -3869,6 +3886,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
63 changes: 63 additions & 0 deletions Zend/zend_vm_def.h
Original file line number Diff line number Diff line change
Expand Up @@ -6370,6 +6370,69 @@ ZEND_VM_C_LABEL(isset_object_finish):
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_P(key) == IS_UNDEF)) {
ZVAL_UNDEFINED_OP1();
}
if (OP2_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(subject) == IS_UNDEF)) {
subject = ZVAL_UNDEFINED_OP2();
}
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_hash_exists_ind(ht, ZSTR_EMPTY_ALLOC());
} else if (Z_TYPE_P(key) <= IS_NULL) {
if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(key) == IS_UNDEF)) {
ZVAL_UNDEFINED_OP1();
}
result = zend_hash_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

1 comment on commit f5044a1

@jmikola
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Related PR, since it didn't get picked up in the commit header: #3360

Please sign in to comment.