}
zend_compile_init_user_func(args->child[0], 0, lcname);
+ if (args->child[1]->kind == ZEND_AST_CALL
+ && args->child[1]->child[0]->kind == ZEND_AST_ZVAL
+ && args->child[1]->child[1]->kind == ZEND_AST_ARG_LIST) {
+ zval *name = zend_ast_get_zval(args->child[1]->child[0]);
+ zend_ast_list *list = zend_ast_get_list(args->child[1]->child[1]);
+
+ if (Z_TYPE_P(name) == IS_STRING
+ && zend_string_equals_literal_ci(Z_STR_P(name), "array_slice")
+ && list->children == 3
+ && list->child[1]->kind == ZEND_AST_ZVAL) {
+ zval *zv = zend_ast_get_zval(list->child[1]);
+
+ if (Z_TYPE_P(zv) == IS_LONG
+ && Z_LVAL_P(zv) >= 0
+ && Z_LVAL_P(zv) <= 0x7fffffff) {
+ zend_op *opline;
+ znode len_node;
+
+ zend_compile_expr(&arg_node, list->child[0]);
+ zend_compile_expr(&len_node, list->child[2]);
+ opline = zend_emit_op(NULL, ZEND_SEND_ARRAY, &arg_node, &len_node);
+ opline->extended_value = Z_LVAL_P(zv);
+ zend_emit_op(result, ZEND_DO_FCALL, NULL, NULL);
+ return SUCCESS;
+ }
+ }
+ }
zend_compile_expr(&arg_node, args->child[1]);
zend_emit_op(NULL, ZEND_SEND_ARRAY, &arg_node, NULL);
zend_emit_op(result, ZEND_DO_FCALL, NULL, NULL);
ZEND_VM_HANDLER(119, ZEND_SEND_ARRAY, ANY, ANY)
{
USE_OPLINE
- zend_free_op free_op1;
- zval *args;
+ zend_free_op free_op1, free_op2;
+ zval *args, *op2;
SAVE_OPLINE();
args = GET_OP1_ZVAL_PTR(BP_VAR_R);
EX(call)->func = (zend_function*)&zend_pass_function;
Z_OBJ(EX(call)->This) = NULL;
ZEND_SET_CALL_INFO(EX(call), 0, ZEND_CALL_INFO(EX(call)) & ~ZEND_CALL_RELEASE_THIS);
+ FREE_UNFETCHED_OP2();
} else {
uint32_t arg_num;
HashTable *ht;
zval *arg, *param;
+
ZEND_VM_C_LABEL(send_array):
ht = Z_ARRVAL_P(args);
- zend_vm_stack_extend_call_frame(&EX(call), 0, zend_hash_num_elements(ht));
+ if (OP2_TYPE != IS_UNUSED) {
+ zend_free_op free_op2;
+ zval *op2 = GET_OP2_ZVAL_PTR_DEREF(BP_VAR_R);
+ uint32_t skip = opline->extended_value;
+ uint32_t count = zend_hash_num_elements(ht);
+ zend_long len = zval_get_long(op2);
+
+ if (len < 0) {
+ len += (zend_long)(count - skip);
+ }
+ if (skip < count && len > 0) {
+ if (len > (zend_long)(count - skip)) {
+ len = (zend_long)(count - skip);
+ }
+ zend_vm_stack_extend_call_frame(&EX(call), 0, len);
+ arg_num = 1;
+ param = ZEND_CALL_ARG(EX(call), 1);
+ ZEND_HASH_FOREACH_VAL(ht, arg) {
+ if (skip > 0) {
+ skip--;
+ continue;
+ } else if ((zend_long)(arg_num - 1) >= len) {
+ break;
+ } else if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
+ if (UNEXPECTED(!Z_ISREF_P(arg))) {
+ if (!ARG_MAY_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
+ /* By-value send is not allowed -- emit a warning,
+ * but still perform the call. */
+ zend_error(E_WARNING,
+ "Parameter %d to %s%s%s() expected to be a reference, value given",
+ arg_num,
+ EX(call)->func->common.scope ? ZSTR_VAL(EX(call)->func->common.scope->name) : "",
+ EX(call)->func->common.scope ? "::" : "",
+ ZSTR_VAL(EX(call)->func->common.function_name));
- arg_num = 1;
- param = ZEND_CALL_ARG(EX(call), 1);
- ZEND_HASH_FOREACH_VAL(ht, arg) {
- if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
- if (UNEXPECTED(!Z_ISREF_P(arg))) {
- if (!ARG_MAY_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
- /* By-value send is not allowed -- emit a warning,
- * but still perform the call. */
- zend_error(E_WARNING,
- "Parameter %d to %s%s%s() expected to be a reference, value given",
- arg_num,
- EX(call)->func->common.scope ? ZSTR_VAL(EX(call)->func->common.scope->name) : "",
- EX(call)->func->common.scope ? "::" : "",
- ZSTR_VAL(EX(call)->func->common.function_name));
+ }
+ }
+ } else {
+ if (Z_ISREF_P(arg) &&
+ !(EX(call)->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) {
+ /* don't separate references for __call */
+ arg = Z_REFVAL_P(arg);
+ }
+ }
+ ZVAL_COPY(param, arg);
+ ZEND_CALL_NUM_ARGS(EX(call))++;
+ arg_num++;
+ param++;
+ } ZEND_HASH_FOREACH_END();
+ }
+ FREE_OP2();
+ } else {
+ zend_vm_stack_extend_call_frame(&EX(call), 0, zend_hash_num_elements(ht));
+ arg_num = 1;
+ param = ZEND_CALL_ARG(EX(call), 1);
+ ZEND_HASH_FOREACH_VAL(ht, arg) {
+ if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
+ if (UNEXPECTED(!Z_ISREF_P(arg))) {
+ if (!ARG_MAY_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
+ /* By-value send is not allowed -- emit a warning,
+ * but still perform the call. */
+ zend_error(E_WARNING,
+ "Parameter %d to %s%s%s() expected to be a reference, value given",
+ arg_num,
+ EX(call)->func->common.scope ? ZSTR_VAL(EX(call)->func->common.scope->name) : "",
+ EX(call)->func->common.scope ? "::" : "",
+ ZSTR_VAL(EX(call)->func->common.function_name));
+ }
+ }
+ } else {
+ if (Z_ISREF_P(arg) &&
+ !(EX(call)->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) {
+ /* don't separate references for __call */
+ arg = Z_REFVAL_P(arg);
}
}
- } else {
- if (Z_ISREF_P(arg) &&
- !(EX(call)->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) {
- /* don't separate references for __call */
- arg = Z_REFVAL_P(arg);
- }
- }
- ZVAL_COPY(param, arg);
- ZEND_CALL_NUM_ARGS(EX(call))++;
- arg_num++;
- param++;
- } ZEND_HASH_FOREACH_END();
+ ZVAL_COPY(param, arg);
+ ZEND_CALL_NUM_ARGS(EX(call))++;
+ arg_num++;
+ param++;
+ } ZEND_HASH_FOREACH_END();
+ }
}
FREE_OP1();
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_ARRAY_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
- zend_free_op free_op1;
- zval *args;
+ zend_free_op free_op1, free_op2;
+ zval *args, *op2;
SAVE_OPLINE();
args = get_zval_ptr(opline->op1_type, opline->op1, execute_data, &free_op1, BP_VAR_R);
EX(call)->func = (zend_function*)&zend_pass_function;
Z_OBJ(EX(call)->This) = NULL;
ZEND_SET_CALL_INFO(EX(call), 0, ZEND_CALL_INFO(EX(call)) & ~ZEND_CALL_RELEASE_THIS);
+ FREE_UNFETCHED_OP(opline->op2_type, opline->op2.var);
} else {
uint32_t arg_num;
HashTable *ht;
zval *arg, *param;
+
send_array:
ht = Z_ARRVAL_P(args);
- zend_vm_stack_extend_call_frame(&EX(call), 0, zend_hash_num_elements(ht));
+ if (opline->op2_type != IS_UNUSED) {
+ zend_free_op free_op2;
+ zval *op2 = get_zval_ptr_deref(opline->op2_type, opline->op2, execute_data, &free_op2, BP_VAR_R);
+ uint32_t skip = opline->extended_value;
+ uint32_t count = zend_hash_num_elements(ht);
+ zend_long len = zval_get_long(op2);
+
+ if (len < 0) {
+ len += (zend_long)(count - skip);
+ }
+ if (skip < count && len > 0) {
+ if (len > (zend_long)(count - skip)) {
+ len = (zend_long)(count - skip);
+ }
+ zend_vm_stack_extend_call_frame(&EX(call), 0, len);
+ arg_num = 1;
+ param = ZEND_CALL_ARG(EX(call), 1);
+ ZEND_HASH_FOREACH_VAL(ht, arg) {
+ if (skip > 0) {
+ skip--;
+ continue;
+ } else if ((zend_long)(arg_num - 1) >= len) {
+ break;
+ } else if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
+ if (UNEXPECTED(!Z_ISREF_P(arg))) {
+ if (!ARG_MAY_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
+ /* By-value send is not allowed -- emit a warning,
+ * but still perform the call. */
+ zend_error(E_WARNING,
+ "Parameter %d to %s%s%s() expected to be a reference, value given",
+ arg_num,
+ EX(call)->func->common.scope ? ZSTR_VAL(EX(call)->func->common.scope->name) : "",
+ EX(call)->func->common.scope ? "::" : "",
+ ZSTR_VAL(EX(call)->func->common.function_name));
- arg_num = 1;
- param = ZEND_CALL_ARG(EX(call), 1);
- ZEND_HASH_FOREACH_VAL(ht, arg) {
- if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
- if (UNEXPECTED(!Z_ISREF_P(arg))) {
- if (!ARG_MAY_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
- /* By-value send is not allowed -- emit a warning,
- * but still perform the call. */
- zend_error(E_WARNING,
- "Parameter %d to %s%s%s() expected to be a reference, value given",
- arg_num,
- EX(call)->func->common.scope ? ZSTR_VAL(EX(call)->func->common.scope->name) : "",
- EX(call)->func->common.scope ? "::" : "",
- ZSTR_VAL(EX(call)->func->common.function_name));
+ }
+ }
+ } else {
+ if (Z_ISREF_P(arg) &&
+ !(EX(call)->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) {
+ /* don't separate references for __call */
+ arg = Z_REFVAL_P(arg);
+ }
+ }
+ ZVAL_COPY(param, arg);
+ ZEND_CALL_NUM_ARGS(EX(call))++;
+ arg_num++;
+ param++;
+ } ZEND_HASH_FOREACH_END();
+ }
+ FREE_OP(free_op2);
+ } else {
+ zend_vm_stack_extend_call_frame(&EX(call), 0, zend_hash_num_elements(ht));
+ arg_num = 1;
+ param = ZEND_CALL_ARG(EX(call), 1);
+ ZEND_HASH_FOREACH_VAL(ht, arg) {
+ if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
+ if (UNEXPECTED(!Z_ISREF_P(arg))) {
+ if (!ARG_MAY_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
+ /* By-value send is not allowed -- emit a warning,
+ * but still perform the call. */
+ zend_error(E_WARNING,
+ "Parameter %d to %s%s%s() expected to be a reference, value given",
+ arg_num,
+ EX(call)->func->common.scope ? ZSTR_VAL(EX(call)->func->common.scope->name) : "",
+ EX(call)->func->common.scope ? "::" : "",
+ ZSTR_VAL(EX(call)->func->common.function_name));
+ }
+ }
+ } else {
+ if (Z_ISREF_P(arg) &&
+ !(EX(call)->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) {
+ /* don't separate references for __call */
+ arg = Z_REFVAL_P(arg);
}
}
- } else {
- if (Z_ISREF_P(arg) &&
- !(EX(call)->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) {
- /* don't separate references for __call */
- arg = Z_REFVAL_P(arg);
- }
- }
- ZVAL_COPY(param, arg);
- ZEND_CALL_NUM_ARGS(EX(call))++;
- arg_num++;
- param++;
- } ZEND_HASH_FOREACH_END();
+ ZVAL_COPY(param, arg);
+ ZEND_CALL_NUM_ARGS(EX(call))++;
+ arg_num++;
+ param++;
+ } ZEND_HASH_FOREACH_END();
+ }
}
FREE_OP(free_op1);
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();