summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikita Popov <nikic@php.net>2014-01-18 14:44:57 +0100
committerNikita Popov <nikic@php.net>2014-01-18 14:44:57 +0100
commit89eab884d9aec3a023ac56289974647c446a0f60 (patch)
treee4a8c9714d4e9b2baf87be89a6e5341c38f5f893
parent84efb8fc718d63c8522b0c1602caa84c84de8db1 (diff)
parent31a2ac470cba47a396a9b6c815700fbec51c6032 (diff)
downloadphp-git-89eab884d9aec3a023ac56289974647c446a0f60.tar.gz
Merge branch 'PHP-5.6'
-rw-r--r--Zend/tests/arg_unpack/many_args.phpt15
-rw-r--r--Zend/zend_execute.c36
-rw-r--r--Zend/zend_vm_def.h8
-rw-r--r--Zend/zend_vm_execute.h8
4 files changed, 63 insertions, 4 deletions
diff --git a/Zend/tests/arg_unpack/many_args.phpt b/Zend/tests/arg_unpack/many_args.phpt
new file mode 100644
index 0000000000..0ef5a30d6d
--- /dev/null
+++ b/Zend/tests/arg_unpack/many_args.phpt
@@ -0,0 +1,15 @@
+--TEST--
+Argument unpacking with many arguments
+--FILE--
+<?php
+
+function fn(...$args) {
+ var_dump(count($args));
+}
+
+$array = array_fill(0, 10000, 42);
+fn(...$array, ...$array);
+
+?>
+--EXPECT--
+int(20000)
diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c
index 174b165c7e..31caceecbe 100644
--- a/Zend/zend_execute.c
+++ b/Zend/zend_execute.c
@@ -1691,6 +1691,42 @@ static zend_always_inline zend_bool zend_is_by_ref_func_arg_fetch(zend_op *oplin
}
/* }}} */
+static void **zend_vm_stack_push_args_with_copy(int count TSRMLS_DC) /* {{{ */
+{
+ zend_vm_stack p = EG(argument_stack);
+
+ zend_vm_stack_extend(count + 1 TSRMLS_CC);
+
+ EG(argument_stack)->top += count;
+ *(EG(argument_stack)->top) = (void*)(zend_uintptr_t)count;
+ while (count-- > 0) {
+ void *data = *(--p->top);
+
+ if (UNEXPECTED(p->top == ZEND_VM_STACK_ELEMETS(p))) {
+ zend_vm_stack r = p;
+
+ EG(argument_stack)->prev = p->prev;
+ p = p->prev;
+ efree(r);
+ }
+ *(ZEND_VM_STACK_ELEMETS(EG(argument_stack)) + count) = data;
+ }
+ return EG(argument_stack)->top++;
+}
+/* }}} */
+
+static zend_always_inline void** zend_vm_stack_push_args(int count TSRMLS_DC) /* {{{ */
+{
+ if (UNEXPECTED(EG(argument_stack)->top - ZEND_VM_STACK_ELEMETS(EG(argument_stack)) < count)
+ || UNEXPECTED(EG(argument_stack)->top == EG(argument_stack)->end)) {
+ return zend_vm_stack_push_args_with_copy(count TSRMLS_CC);
+ }
+ *(EG(argument_stack)->top) = (void*)(zend_uintptr_t)count;
+ return EG(argument_stack)->top++;
+}
+/* }}} */
+
+
#define ZEND_VM_NEXT_OPCODE() \
CHECK_SYMBOL_TABLES() \
ZEND_VM_INC_OPCODE(); \
diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h
index a12f16d1c8..b2cecf229e 100644
--- a/Zend/zend_vm_def.h
+++ b/Zend/zend_vm_def.h
@@ -1947,8 +1947,12 @@ ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY)
}
num_args = opline->extended_value + EX(call)->num_additional_args;
- EX(function_state).arguments = zend_vm_stack_top(TSRMLS_C);
- zend_vm_stack_push((void*)(zend_uintptr_t) num_args TSRMLS_CC);
+ if (EX(call)->num_additional_args) {
+ EX(function_state).arguments = zend_vm_stack_push_args(num_args TSRMLS_CC);
+ } else {
+ EX(function_state).arguments = zend_vm_stack_top(TSRMLS_C);
+ zend_vm_stack_push((void*)(zend_uintptr_t) num_args TSRMLS_CC);
+ }
LOAD_OPLINE();
if (fbc->type == ZEND_INTERNAL_FUNCTION) {
diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h
index 32eec7423a..49d04a2bae 100644
--- a/Zend/zend_vm_execute.h
+++ b/Zend/zend_vm_execute.h
@@ -527,8 +527,12 @@ static int ZEND_FASTCALL zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_AR
}
num_args = opline->extended_value + EX(call)->num_additional_args;
- EX(function_state).arguments = zend_vm_stack_top(TSRMLS_C);
- zend_vm_stack_push((void*)(zend_uintptr_t) num_args TSRMLS_CC);
+ if (EX(call)->num_additional_args) {
+ EX(function_state).arguments = zend_vm_stack_push_args(num_args TSRMLS_CC);
+ } else {
+ EX(function_state).arguments = zend_vm_stack_top(TSRMLS_C);
+ zend_vm_stack_push((void*)(zend_uintptr_t) num_args TSRMLS_CC);
+ }
LOAD_OPLINE();
if (fbc->type == ZEND_INTERNAL_FUNCTION) {