Skip to content

Commit 7c73830

Browse files
committed
Added ZEND_IN_ARRAY instruction, implementing optimized in_array() builtin function, through hash lookup in flipped array
1 parent 5c3d14d commit 7c73830

File tree

6 files changed

+397
-40
lines changed

6 files changed

+397
-40
lines changed

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ PHP NEWS
33
?? ??? ????, PHP 7.2
44

55
- Core:
6+
. Added ZEND_IN_ARRAY instruction, implementing optimized in_array() builtin
7+
function, through hash lookup in flipped array. (Dmitry)
68
. Removed IS_TYPE_IMMUTABLE (it's the same as COPYABLE & !REFCOUNTED). (Dmitry)
79
. Removed the sql.safe_mode directive. (Kalle)
810
. Removed support for Netware. (Kalle)

Zend/zend_compile.c

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ ZEND_API zend_executor_globals executor_globals;
8787
#endif
8888

8989
static zend_op *zend_emit_op(znode *result, zend_uchar opcode, znode *op1, znode *op2);
90+
static zend_bool zend_try_ct_eval_array(zval *result, zend_ast *ast);
9091

9192
static void zend_destroy_property_info_internal(zval *zv) /* {{{ */
9293
{
@@ -2224,6 +2225,7 @@ ZEND_API int zend_is_smart_branch(zend_op *opline) /* {{{ */
22242225
case ZEND_INSTANCEOF:
22252226
case ZEND_TYPE_CHECK:
22262227
case ZEND_DEFINED:
2228+
case ZEND_IN_ARRAY:
22272229
return 1;
22282230
default:
22292231
return 0;
@@ -3635,6 +3637,76 @@ static int zend_compile_assert(znode *result, zend_ast_list *args, zend_string *
36353637
}
36363638
/* }}} */
36373639

3640+
static int zend_compile_func_in_array(znode *result, zend_ast_list *args) /* {{{ */
3641+
{
3642+
zend_bool strict = 0;
3643+
znode array, needly;
3644+
zend_op *opline;
3645+
3646+
if (args->children == 3) {
3647+
if (args->child[2]->kind != ZEND_AST_ZVAL) {
3648+
return FAILURE;
3649+
}
3650+
strict = zend_is_true(zend_ast_get_zval(args->child[2]));
3651+
}
3652+
3653+
if (args->children < 2
3654+
|| args->children > 3
3655+
|| args->child[1]->kind != ZEND_AST_ARRAY
3656+
|| !zend_try_ct_eval_array(&array.u.constant, args->child[1])) {
3657+
return FAILURE;
3658+
}
3659+
3660+
if (zend_hash_num_elements(Z_ARRVAL(array.u.constant)) > 0) {
3661+
zend_bool ok = 1;
3662+
zval *val, tmp;
3663+
zend_ulong idx;
3664+
HashTable *src = Z_ARRVAL(array.u.constant);
3665+
HashTable *dst = emalloc(sizeof(HashTable));
3666+
3667+
zend_hash_init(dst, zend_hash_num_elements(src), NULL, ZVAL_PTR_DTOR, 0);
3668+
ZVAL_TRUE(&tmp);
3669+
3670+
if (strict) {
3671+
ZEND_HASH_FOREACH_VAL(src, val) {
3672+
if (Z_TYPE_P(val) == IS_STRING) {
3673+
zend_hash_add(dst, Z_STR_P(val), &tmp);
3674+
} else if (Z_TYPE_P(val) == IS_LONG) {
3675+
zend_hash_index_add(dst, Z_LVAL_P(val), &tmp);
3676+
} else {
3677+
zend_array_destroy(dst);
3678+
ok = 0;
3679+
break;
3680+
}
3681+
} ZEND_HASH_FOREACH_END();
3682+
} else {
3683+
ZEND_HASH_FOREACH_VAL(src, val) {
3684+
if (Z_TYPE_P(val) != IS_STRING || ZEND_HANDLE_NUMERIC(Z_STR_P(val), idx)) {
3685+
zend_array_destroy(dst);
3686+
ok = 0;
3687+
break;
3688+
}
3689+
zend_hash_add(dst, Z_STR_P(val), &tmp);
3690+
} ZEND_HASH_FOREACH_END();
3691+
}
3692+
3693+
zend_array_destroy(src);
3694+
if (!ok) {
3695+
return FAILURE;
3696+
}
3697+
Z_ARRVAL(array.u.constant) = dst;
3698+
}
3699+
array.op_type = IS_CONST;
3700+
3701+
zend_compile_expr(&needly, args->child[0]);
3702+
3703+
opline = zend_emit_op_tmp(result, ZEND_IN_ARRAY, &needly, &array);
3704+
opline->extended_value = strict;
3705+
3706+
return SUCCESS;
3707+
}
3708+
/* }}} */
3709+
36383710
int zend_try_compile_special_func(znode *result, zend_string *lcname, zend_ast_list *args, zend_function *fbc, uint32_t type) /* {{{ */
36393711
{
36403712
if (fbc->internal_function.handler == ZEND_FN(display_disabled_function)) {
@@ -3693,6 +3765,8 @@ int zend_try_compile_special_func(znode *result, zend_string *lcname, zend_ast_l
36933765
return zend_compile_func_cufa(result, args, lcname);
36943766
} else if (zend_string_equals_literal(lcname, "call_user_func")) {
36953767
return zend_compile_func_cuf(result, args, lcname);
3768+
} else if (zend_string_equals_literal(lcname, "in_array")) {
3769+
return zend_compile_func_in_array(result, args);
36963770
} else {
36973771
return FAILURE;
36983772
}

Zend/zend_vm_def.h

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8102,6 +8102,49 @@ ZEND_VM_HANDLER(188, ZEND_SWITCH_STRING, CONST|TMPVAR|CV, CONST, JMP_ADDR)
81028102
}
81038103
}
81048104

8105+
ZEND_VM_HANDLER(189, ZEND_IN_ARRAY, CONST|TMP|VAR|CV, CONST, NUM)
8106+
{
8107+
USE_OPLINE
8108+
zend_free_op free_op1;
8109+
zval *op1 = GET_OP1_ZVAL_PTR_DEREF(BP_VAR_R);
8110+
HashTable *ht = Z_ARRVAL_P(EX_CONSTANT(opline->op2));
8111+
int result;
8112+
8113+
if (EXPECTED(Z_TYPE_P(op1) == IS_STRING)) {
8114+
result = zend_hash_exists(ht, Z_STR_P(op1));
8115+
} else if (opline->extended_value) {
8116+
if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) {
8117+
result = zend_hash_index_exists(ht, Z_LVAL_P(op1));
8118+
} else {
8119+
result = 0;
8120+
}
8121+
} else if (Z_TYPE_P(op1) <= IS_FALSE) {
8122+
result = zend_hash_exists(ht, ZSTR_EMPTY_ALLOC());
8123+
} else {
8124+
zend_string *key;
8125+
zval tmp;
8126+
8127+
result = 0;
8128+
SAVE_OPLINE();
8129+
ZEND_HASH_FOREACH_STR_KEY(ht, key) {
8130+
ZVAL_STR(&tmp, key);
8131+
compare_function(&tmp, op1, &tmp);
8132+
if (Z_LVAL(tmp) == 0) {
8133+
result = 1;
8134+
break;
8135+
}
8136+
} ZEND_HASH_FOREACH_END();
8137+
FREE_OP1();
8138+
ZEND_VM_SMART_BRANCH(result, 1);
8139+
ZVAL_BOOL(EX_VAR(opline->result.var), result);
8140+
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
8141+
}
8142+
FREE_OP1();
8143+
ZEND_VM_SMART_BRANCH(result, 0);
8144+
ZVAL_BOOL(EX_VAR(opline->result.var), result);
8145+
ZEND_VM_NEXT_OPCODE();
8146+
}
8147+
81058148
ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_ADD, (res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG && op2_info == MAY_BE_LONG), ZEND_ADD_LONG_NO_OVERFLOW, CONST|TMPVARCV, CONST|TMPVARCV, SPEC(NO_CONST_CONST,COMMUTATIVE))
81068149
{
81078150
USE_OPLINE

0 commit comments

Comments
 (0)