diff options
| author | Nikita Popov <nikic@php.net> | 2014-01-18 14:44:57 +0100 |
|---|---|---|
| committer | Nikita Popov <nikic@php.net> | 2014-01-18 14:44:57 +0100 |
| commit | 89eab884d9aec3a023ac56289974647c446a0f60 (patch) | |
| tree | e4a8c9714d4e9b2baf87be89a6e5341c38f5f893 | |
| parent | 84efb8fc718d63c8522b0c1602caa84c84de8db1 (diff) | |
| parent | 31a2ac470cba47a396a9b6c815700fbec51c6032 (diff) | |
| download | php-git-89eab884d9aec3a023ac56289974647c446a0f60.tar.gz | |
Merge branch 'PHP-5.6'
| -rw-r--r-- | Zend/tests/arg_unpack/many_args.phpt | 15 | ||||
| -rw-r--r-- | Zend/zend_execute.c | 36 | ||||
| -rw-r--r-- | Zend/zend_vm_def.h | 8 | ||||
| -rw-r--r-- | Zend/zend_vm_execute.h | 8 |
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) { |
