From f445a7d09670affbc07be40d70fb641d4715456b Mon Sep 17 00:00:00 2001 From: Joe Watkins Date: Tue, 20 Apr 2021 01:43:36 +0200 Subject: [PATCH 01/35] partial application --- Zend/Optimizer/zend_call_graph.c | 2 + .../compile_errors_001.phpt | 9 + .../compile_errors_002.phpt | 9 + .../compile_errors_003.phpt | 9 + .../compile_errors_004.phpt | 8 + .../compile_errors_005.phpt | 9 + .../compile_errors_006.phpt | 9 + .../compile_errors_007.phpt | 9 + .../tests/partial_application/errors_001.phpt | 38 + .../tests/partial_application/errors_002.phpt | 17 + .../tests/partial_application/errors_003.phpt | 65 ++ .../tests/partial_application/export_001.phpt | 14 + .../extra_collect_001.phpt | 50 + .../partial_application/factory_001.phpt | 24 + .../partial_application/factory_002.phpt | 30 + .../partial_application/factory_003.phpt | 24 + .../partial_application/factory_004.phpt | 18 + Zend/tests/partial_application/magic_001.phpt | 27 + Zend/tests/partial_application/magic_002.phpt | 25 + .../partial_application/reflection_001.phpt | 62 ++ .../partial_application/reflection_002.phpt | 57 ++ .../partial_application/reflection_003.phpt | 41 + .../partial_application/return_type_001.phpt | 17 + .../static_method_001.phpt | 18 + .../partial_application/statics_001.phpt | 22 + Zend/tests/partial_application/this_001.phpt | 22 + .../variation_apply_002.phpt | 18 + .../variation_closure_001.phpt | 19 + .../variation_closure_002.phpt | 23 + .../variation_closure_003.phpt | 42 + .../variation_debug_001.phpt | 36 + .../variation_debug_002.phpt | 46 + .../variation_factory_001.phpt | 17 + .../partial_application/variation_gc_001.phpt | 18 + .../variation_invoke_001.phpt | 23 + .../variation_parent_001.phpt | 45 + .../variation_pass_001.phpt | 14 + .../variation_strict_001.phpt | 21 + .../variation_variadics_001.phpt | 26 + .../variation_variadics_002.phpt | 19 + .../variation_variadics_003.phpt | 50 + .../variation_variadics_004.phpt | 65 ++ .../variation_variadics_006.phpt | 18 + Zend/zend.c | 3 + Zend/zend_ast.c | 7 + Zend/zend_ast.h | 1 + Zend/zend_closures.c | 28 +- Zend/zend_closures.h | 1 + Zend/zend_compile.c | 103 +- Zend/zend_compile.h | 9 +- Zend/zend_execute.c | 19 +- Zend/zend_language_parser.y | 4 + Zend/zend_object_handlers.h | 2 +- Zend/zend_partial.c | 876 ++++++++++++++++++ Zend/zend_partial.h | 38 + Zend/zend_types.h | 4 + Zend/zend_vm_def.h | 85 +- Zend/zend_vm_execute.h | 196 +++- Zend/zend_vm_handlers.h | 731 +++++++-------- Zend/zend_vm_opcodes.c | 10 +- Zend/zend_vm_opcodes.h | 5 +- configure.ac | 2 +- ext/reflection/php_reflection.c | 72 +- win32/build/config.w32 | 2 +- 64 files changed, 2890 insertions(+), 443 deletions(-) create mode 100644 Zend/tests/partial_application/compile_errors_001.phpt create mode 100644 Zend/tests/partial_application/compile_errors_002.phpt create mode 100644 Zend/tests/partial_application/compile_errors_003.phpt create mode 100644 Zend/tests/partial_application/compile_errors_004.phpt create mode 100644 Zend/tests/partial_application/compile_errors_005.phpt create mode 100644 Zend/tests/partial_application/compile_errors_006.phpt create mode 100644 Zend/tests/partial_application/compile_errors_007.phpt create mode 100644 Zend/tests/partial_application/errors_001.phpt create mode 100644 Zend/tests/partial_application/errors_002.phpt create mode 100644 Zend/tests/partial_application/errors_003.phpt create mode 100644 Zend/tests/partial_application/export_001.phpt create mode 100644 Zend/tests/partial_application/extra_collect_001.phpt create mode 100644 Zend/tests/partial_application/factory_001.phpt create mode 100644 Zend/tests/partial_application/factory_002.phpt create mode 100644 Zend/tests/partial_application/factory_003.phpt create mode 100644 Zend/tests/partial_application/factory_004.phpt create mode 100644 Zend/tests/partial_application/magic_001.phpt create mode 100644 Zend/tests/partial_application/magic_002.phpt create mode 100644 Zend/tests/partial_application/reflection_001.phpt create mode 100644 Zend/tests/partial_application/reflection_002.phpt create mode 100644 Zend/tests/partial_application/reflection_003.phpt create mode 100644 Zend/tests/partial_application/return_type_001.phpt create mode 100644 Zend/tests/partial_application/static_method_001.phpt create mode 100644 Zend/tests/partial_application/statics_001.phpt create mode 100644 Zend/tests/partial_application/this_001.phpt create mode 100644 Zend/tests/partial_application/variation_apply_002.phpt create mode 100644 Zend/tests/partial_application/variation_closure_001.phpt create mode 100644 Zend/tests/partial_application/variation_closure_002.phpt create mode 100644 Zend/tests/partial_application/variation_closure_003.phpt create mode 100644 Zend/tests/partial_application/variation_debug_001.phpt create mode 100644 Zend/tests/partial_application/variation_debug_002.phpt create mode 100644 Zend/tests/partial_application/variation_factory_001.phpt create mode 100644 Zend/tests/partial_application/variation_gc_001.phpt create mode 100644 Zend/tests/partial_application/variation_invoke_001.phpt create mode 100644 Zend/tests/partial_application/variation_parent_001.phpt create mode 100644 Zend/tests/partial_application/variation_pass_001.phpt create mode 100644 Zend/tests/partial_application/variation_strict_001.phpt create mode 100644 Zend/tests/partial_application/variation_variadics_001.phpt create mode 100644 Zend/tests/partial_application/variation_variadics_002.phpt create mode 100644 Zend/tests/partial_application/variation_variadics_003.phpt create mode 100644 Zend/tests/partial_application/variation_variadics_004.phpt create mode 100644 Zend/tests/partial_application/variation_variadics_006.phpt create mode 100644 Zend/zend_partial.c create mode 100644 Zend/zend_partial.h diff --git a/Zend/Optimizer/zend_call_graph.c b/Zend/Optimizer/zend_call_graph.c index 1f290c5e00470..aa78fa9f4c838 100644 --- a/Zend/Optimizer/zend_call_graph.c +++ b/Zend/Optimizer/zend_call_graph.c @@ -106,6 +106,7 @@ ZEND_API int zend_analyze_calls(zend_arena **arena, zend_script *script, uint32_ case ZEND_DO_ICALL: case ZEND_DO_UCALL: case ZEND_DO_FCALL_BY_NAME: + case ZEND_DO_FCALL_PARTIAL: func_info->flags |= ZEND_FUNC_HAS_CALLS; if (call_info) { call_info->caller_call_opline = opline; @@ -122,6 +123,7 @@ ZEND_API int zend_analyze_calls(zend_arena **arena, zend_script *script, uint32_ case ZEND_SEND_VAR_NO_REF: case ZEND_SEND_VAR_NO_REF_EX: case ZEND_SEND_USER: + case ZEND_SEND_PLACEHOLDER: if (call_info) { if (opline->op2_type == IS_CONST) { call_info->named_args = 1; diff --git a/Zend/tests/partial_application/compile_errors_001.phpt b/Zend/tests/partial_application/compile_errors_001.phpt new file mode 100644 index 0000000000000..8d5587851d500 --- /dev/null +++ b/Zend/tests/partial_application/compile_errors_001.phpt @@ -0,0 +1,9 @@ +--TEST-- +Partial application compile errors: multiple ... +--FILE-- + +--EXPECTF-- +Fatal error: Variadic place holder may only appear once in %s on line %d + diff --git a/Zend/tests/partial_application/compile_errors_002.phpt b/Zend/tests/partial_application/compile_errors_002.phpt new file mode 100644 index 0000000000000..4f5d2a552af29 --- /dev/null +++ b/Zend/tests/partial_application/compile_errors_002.phpt @@ -0,0 +1,9 @@ +--TEST-- +Partial application compile errors: only named arguments after ... +--FILE-- + +--EXPECTF-- +Fatal error: Only named arguments may follow variadic place holder in %s on line %d + diff --git a/Zend/tests/partial_application/compile_errors_003.phpt b/Zend/tests/partial_application/compile_errors_003.phpt new file mode 100644 index 0000000000000..16596a38839dc --- /dev/null +++ b/Zend/tests/partial_application/compile_errors_003.phpt @@ -0,0 +1,9 @@ +--TEST-- +Partial application compile errors: named arguments must come after place holder +--FILE-- + +--EXPECTF-- +Fatal error: Named arguments must come after all place holders in %s on line %d + diff --git a/Zend/tests/partial_application/compile_errors_004.phpt b/Zend/tests/partial_application/compile_errors_004.phpt new file mode 100644 index 0000000000000..91cb3af63c042 --- /dev/null +++ b/Zend/tests/partial_application/compile_errors_004.phpt @@ -0,0 +1,8 @@ +--TEST-- +Partial application compile errors: named arguments must come after variadic place holder +--FILE-- + +--EXPECTF-- +Fatal error: Named arguments must come after all place holders in %s on line %d diff --git a/Zend/tests/partial_application/compile_errors_005.phpt b/Zend/tests/partial_application/compile_errors_005.phpt new file mode 100644 index 0000000000000..3073eda24d479 --- /dev/null +++ b/Zend/tests/partial_application/compile_errors_005.phpt @@ -0,0 +1,9 @@ +--TEST-- +Partial application compile errors: follow variadic with un-named arg +--FILE-- + +--EXPECTF-- +Fatal error: Only named arguments may follow variadic place holder in %s on line %d + diff --git a/Zend/tests/partial_application/compile_errors_006.phpt b/Zend/tests/partial_application/compile_errors_006.phpt new file mode 100644 index 0000000000000..5f240afa1135f --- /dev/null +++ b/Zend/tests/partial_application/compile_errors_006.phpt @@ -0,0 +1,9 @@ +--TEST-- +Partial application compile errors: mix application with unpack (place holder after) +--FILE-- + "bar"], ...); +?> +--EXPECTF-- +Fatal error: Cannot combine partial application and unpacking %s on line %d + diff --git a/Zend/tests/partial_application/compile_errors_007.phpt b/Zend/tests/partial_application/compile_errors_007.phpt new file mode 100644 index 0000000000000..765d44dcfd58a --- /dev/null +++ b/Zend/tests/partial_application/compile_errors_007.phpt @@ -0,0 +1,9 @@ +--TEST-- +Partial application compile errors: mix application with unpack (place holder before) +--FILE-- + "bar"]); +?> +--EXPECTF-- +Fatal error: Cannot combine partial application and unpacking %s on line %d + diff --git a/Zend/tests/partial_application/errors_001.phpt b/Zend/tests/partial_application/errors_001.phpt new file mode 100644 index 0000000000000..e709ba207c489 --- /dev/null +++ b/Zend/tests/partial_application/errors_001.phpt @@ -0,0 +1,38 @@ +--TEST-- +Partial application errors: place holder count errors +--FILE-- +getMessage()); +} + +try { + foo(?, ?, ?, ?); +} catch (Error $ex) { + printf("%s\n", $ex->getMessage()); +} + +try { + property_exists(?); +} catch (Error $ex) { + printf("%s\n", $ex->getMessage()); +} + +try { + usleep(?, ?); +} catch (Error $ex) { + printf("%s\n", $ex->getMessage()); +} +?> +--EXPECTF-- +not enough arguments and or place holders for application of foo, 1 given and exactly 3 expected, declared in %s on line 2 +too many arguments and or place holders for application of foo, 4 given and a maximum of 3 expected, declared in %s on line 2 +not enough arguments and or place holders for application of property_exists, 1 given and exactly 2 expected +too many arguments and or place holders for application of usleep, 2 given and a maximum of 1 expected + diff --git a/Zend/tests/partial_application/errors_002.phpt b/Zend/tests/partial_application/errors_002.phpt new file mode 100644 index 0000000000000..88e7a7ba8f87a --- /dev/null +++ b/Zend/tests/partial_application/errors_002.phpt @@ -0,0 +1,17 @@ +--TEST-- +Partial application errors: named parameter overwrites place holder +--FILE-- +getMessage()); +} +?> +--EXPECT-- +Named parameter $a overwrites previous place holder + diff --git a/Zend/tests/partial_application/errors_003.phpt b/Zend/tests/partial_application/errors_003.phpt new file mode 100644 index 0000000000000..15b32592208bc --- /dev/null +++ b/Zend/tests/partial_application/errors_003.phpt @@ -0,0 +1,65 @@ +--TEST-- +Partial application errors: missing parameters +--FILE-- +getMessage()); +} + +$foo = foo(?, ?); + +try { + $foo(1); +} catch (Error $ex) { + printf("%s\n", $ex->getMessage()); +} + +$bar = bar(?, ?, ...); + +try { + $bar(1); +} catch (Error $ex) { + printf("%s\n", $ex->getMessage()); +} + +$usleep = usleep(...); + +try { + $usleep(); +} catch (Error $ex) { + printf("%s\n", $ex->getMessage()); +} + +class Foo { + public function bar($a, ...$b) {} +} + +$foo = new Foo; + +$bar = $foo->bar(?); + +try { + $bar(); +} catch (Error $ex) { + printf("%s\n", $ex->getMessage()); +} + +?> +--EXPECTF-- +not enough arguments for application of foo, 0 given and exactly 1 expected, declared in %s on line 8 +not enough arguments for application of foo, 1 given and exactly 2 expected, declared in %s on line 16 +not enough arguments for application of bar, 1 given and at least 2 expected, declared in %s on line 24 +not enough arguments for implementation of usleep, 0 given and exactly 1 expected +not enough arguments for application of Foo::bar, 0 given and exactly 1 expected, declared in %s on line 46 + + diff --git a/Zend/tests/partial_application/export_001.phpt b/Zend/tests/partial_application/export_001.phpt new file mode 100644 index 0000000000000..a4af669148b14 --- /dev/null +++ b/Zend/tests/partial_application/export_001.phpt @@ -0,0 +1,14 @@ +--TEST-- +Partial application ast export +--INI-- +assert.exception=1 +--FILE-- +getMessage()); +} +?> +--EXPECT-- +assert(0 && foo(?) && foo(...)) diff --git a/Zend/tests/partial_application/extra_collect_001.phpt b/Zend/tests/partial_application/extra_collect_001.phpt new file mode 100644 index 0000000000000..c5b44576f0e15 --- /dev/null +++ b/Zend/tests/partial_application/extra_collect_001.phpt @@ -0,0 +1,50 @@ +--TEST-- +Partial application named parameters: extra collection +--FILE-- + +--EXPECT-- +array(3) { + ["foo"]=> + string(3) "foo" + ["bar"]=> + string(3) "bar" + ["baz"]=> + string(3) "baz" +} +array(2) { + ["bar"]=> + string(3) "bar" + ["baz"]=> + string(3) "baz" +} +array(2) { + ["foo"]=> + string(3) "foo" + ["bar"]=> + string(3) "bar" +} + diff --git a/Zend/tests/partial_application/factory_001.phpt b/Zend/tests/partial_application/factory_001.phpt new file mode 100644 index 0000000000000..ad34aebd027f1 --- /dev/null +++ b/Zend/tests/partial_application/factory_001.phpt @@ -0,0 +1,24 @@ +--TEST-- +Partial application factory: pass +--FILE-- + +--EXPECTF-- +OK +Foo::__destruct +Foo::__destruct diff --git a/Zend/tests/partial_application/factory_002.phpt b/Zend/tests/partial_application/factory_002.phpt new file mode 100644 index 0000000000000..2b94ead0379a1 --- /dev/null +++ b/Zend/tests/partial_application/factory_002.phpt @@ -0,0 +1,30 @@ +--TEST-- +Partial application factory: normal +--FILE-- + +--EXPECTF-- +Foo::__construct +Foo::__construct +OK +Foo::__destruct +Foo::__destruct diff --git a/Zend/tests/partial_application/factory_003.phpt b/Zend/tests/partial_application/factory_003.phpt new file mode 100644 index 0000000000000..fb752b299b6c5 --- /dev/null +++ b/Zend/tests/partial_application/factory_003.phpt @@ -0,0 +1,24 @@ +--TEST-- +Partial application factory: exception +--FILE-- +getMessage()); +} +?> +--EXPECT-- +boo diff --git a/Zend/tests/partial_application/factory_004.phpt b/Zend/tests/partial_application/factory_004.phpt new file mode 100644 index 0000000000000..dd46d203aacde --- /dev/null +++ b/Zend/tests/partial_application/factory_004.phpt @@ -0,0 +1,18 @@ +--TEST-- +Partial application factory object properties initialization +--FILE-- + +--EXPECTF-- +object(Foo)#%d (1) { + ["arg"]=> + int(1) +} + diff --git a/Zend/tests/partial_application/magic_001.phpt b/Zend/tests/partial_application/magic_001.phpt new file mode 100644 index 0000000000000..56488a526cbfc --- /dev/null +++ b/Zend/tests/partial_application/magic_001.phpt @@ -0,0 +1,27 @@ +--TEST-- +Partial application magic: __call +--FILE-- +method(?); + +echo (string) new ReflectionFunction($bar); + +$bar(1); +?> +--EXPECTF-- +Method [ partial public method method ] { + @@ %s 10 - 10 + + - Parameters [1] { + Parameter #0 [ $args ] + } +} +Foo::method diff --git a/Zend/tests/partial_application/magic_002.phpt b/Zend/tests/partial_application/magic_002.phpt new file mode 100644 index 0000000000000..928f541ce4868 --- /dev/null +++ b/Zend/tests/partial_application/magic_002.phpt @@ -0,0 +1,25 @@ +--TEST-- +Partial application magic: __callStatic +--FILE-- + +--EXPECTF-- +Method [ partial static public method method ] { + @@ %s 8 - 8 + + - Parameters [1] { + Parameter #0 [ $args ] + } +} +Foo::method diff --git a/Zend/tests/partial_application/reflection_001.phpt b/Zend/tests/partial_application/reflection_001.phpt new file mode 100644 index 0000000000000..e9f77a778687b --- /dev/null +++ b/Zend/tests/partial_application/reflection_001.phpt @@ -0,0 +1,62 @@ +--TEST-- +Partial application reflection: required parameters +--FILE-- + +--EXPECTF-- +Function [ partial function foo ] { + @@ %s 6 - 6 + + - Parameters [3] { + Parameter #0 [ $a = 1 ] + Parameter #1 [ $b = 5 ] + Parameter #2 [ $c = 10 ] + } +} +Function [ partial function foo ] { + @@ %s 10 - 10 + + - Parameters [3] { + Parameter #0 [ $a ] + Parameter #1 [ $b = 5 ] + Parameter #2 [ $c = 10 ] + } +} +Function [ partial function foo ] { + @@ %s 14 - 14 + + - Parameters [3] { + Parameter #0 [ $a ] + Parameter #1 [ $b ] + Parameter #2 [ $c = 10 ] + } +} +Function [ partial function foo ] { + @@ %s 18 - 18 + + - Parameters [3] { + Parameter #0 [ $a ] + Parameter #1 [ $b ] + Parameter #2 [ $c ] + } +} + diff --git a/Zend/tests/partial_application/reflection_002.phpt b/Zend/tests/partial_application/reflection_002.phpt new file mode 100644 index 0000000000000..dbdbc56e815a2 --- /dev/null +++ b/Zend/tests/partial_application/reflection_002.phpt @@ -0,0 +1,57 @@ +--TEST-- +Partial application reflection: variadics +--FILE-- + +--EXPECTF-- +Function [ partial function foo ] { + @@ %s 6 - 6 + + - Parameters [1] { + Parameter #0 [ $a ] + } +} +Function [ partial function foo ] { + @@ %s 10 - 10 + + - Parameters [2] { + Parameter #0 [ $a ] + Parameter #1 [ ...$b ] + } +} +Function [ partial function foo ] { + @@ %s 14 - 14 + + - Parameters [2] { + Parameter #0 [ $a ] + Parameter #1 [ $b ] + } +} +Function [ partial function foo ] { + @@ %s 18 - 18 + + - Parameters [3] { + Parameter #0 [ $a ] + Parameter #1 [ $b ] + Parameter #2 [ $b ] + } +} diff --git a/Zend/tests/partial_application/reflection_003.phpt b/Zend/tests/partial_application/reflection_003.phpt new file mode 100644 index 0000000000000..cd117c94ecf60 --- /dev/null +++ b/Zend/tests/partial_application/reflection_003.phpt @@ -0,0 +1,41 @@ +--TEST-- +Partial application reflection: internal with variadics +--FILE-- + +--EXPECTF-- +Function [ partial function sprintf ] { + + - Parameters [1] { + Parameter #0 [ string $format ] + } + - Return [ string ] +} +Function [ partial function sprintf ] { + + - Parameters [2] { + Parameter #0 [ string $format ] + Parameter #1 [ mixed ...$values ] + } + - Return [ string ] +} +Function [ partial function sprintf ] { + + - Parameters [2] { + Parameter #0 [ string $format ] + Parameter #1 [ mixed $values ] + } + - Return [ string ] +} + diff --git a/Zend/tests/partial_application/return_type_001.phpt b/Zend/tests/partial_application/return_type_001.phpt new file mode 100644 index 0000000000000..af7826ff160ad --- /dev/null +++ b/Zend/tests/partial_application/return_type_001.phpt @@ -0,0 +1,17 @@ +--TEST-- +Partial application return type +--FILE-- + +--EXPECTF-- +Function [ partial function foo ] { + @@ %s 4 - 4 + + - Parameters [0] { + } + - Return [ array ] +} + diff --git a/Zend/tests/partial_application/static_method_001.phpt b/Zend/tests/partial_application/static_method_001.phpt new file mode 100644 index 0000000000000..a690873499ba0 --- /dev/null +++ b/Zend/tests/partial_application/static_method_001.phpt @@ -0,0 +1,18 @@ +--TEST-- +Partial application static method +--FILE-- + +--EXPECTF-- +Foo::method diff --git a/Zend/tests/partial_application/statics_001.phpt b/Zend/tests/partial_application/statics_001.phpt new file mode 100644 index 0000000000000..c4edc8eaceb7a --- /dev/null +++ b/Zend/tests/partial_application/statics_001.phpt @@ -0,0 +1,22 @@ +--TEST-- +Partial application static variables shared +--FILE-- + +--EXPECTF-- +OK diff --git a/Zend/tests/partial_application/this_001.phpt b/Zend/tests/partial_application/this_001.phpt new file mode 100644 index 0000000000000..2113d9e78a0fd --- /dev/null +++ b/Zend/tests/partial_application/this_001.phpt @@ -0,0 +1,22 @@ +--TEST-- +Partial application this +--FILE-- +method(...); + +$baz = $bar(...); + +var_dump($baz()); +?> +--EXPECTF-- +object(Foo)#%d (0) { +} + diff --git a/Zend/tests/partial_application/variation_apply_002.phpt b/Zend/tests/partial_application/variation_apply_002.phpt new file mode 100644 index 0000000000000..abdf24788081a --- /dev/null +++ b/Zend/tests/partial_application/variation_apply_002.phpt @@ -0,0 +1,18 @@ +--TEST-- +Partial application variation type +--FILE-- + +--EXPECT-- +Foo::__construct diff --git a/Zend/tests/partial_application/variation_closure_001.phpt b/Zend/tests/partial_application/variation_closure_001.phpt new file mode 100644 index 0000000000000..c9e7ea96f55d8 --- /dev/null +++ b/Zend/tests/partial_application/variation_closure_001.phpt @@ -0,0 +1,19 @@ +--TEST-- +Partial application variation closure +--FILE-- + +--EXPECTF-- +Function [ partial function {closure} ] { + @@ %s 6 - 6 + + - Parameters [1] { + Parameter #0 [ $b ] + } +} + diff --git a/Zend/tests/partial_application/variation_closure_002.phpt b/Zend/tests/partial_application/variation_closure_002.phpt new file mode 100644 index 0000000000000..572c8bd0a674f --- /dev/null +++ b/Zend/tests/partial_application/variation_closure_002.phpt @@ -0,0 +1,23 @@ +--TEST-- +Partial application variation closure __invoke +--FILE-- +__invoke(1, ?); + +echo (string) new ReflectionFunction($function); + +$function(10); +?> +--EXPECTF-- +Method [ partial public method __invoke ] { + + - Parameters [1] { + Parameter #0 [ $b ] + } +} +int(1) +int(10) diff --git a/Zend/tests/partial_application/variation_closure_003.phpt b/Zend/tests/partial_application/variation_closure_003.phpt new file mode 100644 index 0000000000000..f1363efaf7b32 --- /dev/null +++ b/Zend/tests/partial_application/variation_closure_003.phpt @@ -0,0 +1,42 @@ +--TEST-- +Partial application variation closure __invoke with this +--FILE-- +bar(); + +$function = $closure->__invoke(1, ?); + +echo (string) new ReflectionFunction($function); + +var_dump($function(10)); +?> +--EXPECTF-- +Method [ partial public method __invoke ] { + + - Parameters [1] { + Parameter #0 [ $b ] + } +} +array(2) { + [0]=> + object(Foo)#1 (0) { + } + [1]=> + array(2) { + [0]=> + int(1) + [1]=> + int(10) + } +} + diff --git a/Zend/tests/partial_application/variation_debug_001.phpt b/Zend/tests/partial_application/variation_debug_001.phpt new file mode 100644 index 0000000000000..6981885c09e7d --- /dev/null +++ b/Zend/tests/partial_application/variation_debug_001.phpt @@ -0,0 +1,36 @@ +--TEST-- +Partial application variation debug user +--FILE-- + +--EXPECTF-- +object(Closure)#%d (2) { + ["parameter"]=> + array(1) { + ["$a"]=> + string(10) "" + } + ["args"]=> + array(3) { + ["a"]=> + NULL + ["b"]=> + object(stdClass)#%d (0) { + } + ["c"]=> + array(3) { + [0]=> + int(20) + [1]=> + object(stdClass)#%d (0) { + } + ["four"]=> + int(4) + } + } +} diff --git a/Zend/tests/partial_application/variation_debug_002.phpt b/Zend/tests/partial_application/variation_debug_002.phpt new file mode 100644 index 0000000000000..ed40f8222911f --- /dev/null +++ b/Zend/tests/partial_application/variation_debug_002.phpt @@ -0,0 +1,46 @@ +--TEST-- +Partial application variation debug internal +--FILE-- + +--EXPECTF-- +object(Closure)#%d (2) { + ["parameter"]=> + array(2) { + ["$callback"]=> + string(10) "" + ["$arrays"]=> + string(10) "" + } + ["args"]=> + array(3) { + ["callback"]=> + NULL + ["array"]=> + array(3) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + int(3) + } + ["arrays"]=> + array(2) { + [0]=> + array(3) { + [0]=> + int(4) + [1]=> + int(5) + [2]=> + int(6) + } + ["four"]=> + object(stdClass)#%d (0) { + } + } + } +} + diff --git a/Zend/tests/partial_application/variation_factory_001.phpt b/Zend/tests/partial_application/variation_factory_001.phpt new file mode 100644 index 0000000000000..52c73749bd901 --- /dev/null +++ b/Zend/tests/partial_application/variation_factory_001.phpt @@ -0,0 +1,17 @@ +--TEST-- +Partial application variation internal object factory +--FILE-- +getTimeZone()); +?> +--EXPECTF-- +object(DateTimeZone)#%d (2) { + ["timezone_type"]=> + int(3) + ["timezone"]=> + string(10) "Asia/Tokyo" +} + diff --git a/Zend/tests/partial_application/variation_gc_001.phpt b/Zend/tests/partial_application/variation_gc_001.phpt new file mode 100644 index 0000000000000..00b951a81ea9f --- /dev/null +++ b/Zend/tests/partial_application/variation_gc_001.phpt @@ -0,0 +1,18 @@ +--TEST-- +Partial application variation GC +--FILE-- +method = self::__construct(...); + } +} + +$foo = new Foo; +$foo->bar = $foo; + +echo "OK"; +?> +--EXPECT-- +OK diff --git a/Zend/tests/partial_application/variation_invoke_001.phpt b/Zend/tests/partial_application/variation_invoke_001.phpt new file mode 100644 index 0000000000000..eed2ad12b17b4 --- /dev/null +++ b/Zend/tests/partial_application/variation_invoke_001.phpt @@ -0,0 +1,23 @@ +--TEST-- +Partial application variation __invoke +--FILE-- +__invoke(32) == 42) { + echo "OK\n"; +} + +try { + $foo->nothing(); +} catch (Error $ex) { + echo "OK"; +} +?> +--EXPECT-- +OK +OK diff --git a/Zend/tests/partial_application/variation_parent_001.phpt b/Zend/tests/partial_application/variation_parent_001.phpt new file mode 100644 index 0000000000000..efb77fff1f71b --- /dev/null +++ b/Zend/tests/partial_application/variation_parent_001.phpt @@ -0,0 +1,45 @@ +--TEST-- +Partial application variation parent +--FILE-- +method(10, ...); +$baz = $bar(20, ...); + +var_dump($baz, $baz()); +?> +--EXPECTF-- +object(Closure)#%d (3) { + ["this"]=> + object(Foo)#%d (0) { + } + ["parameter"]=> + array(1) { + ["$c"]=> + string(10) "" + } + ["args"]=> + array(3) { + ["a"]=> + int(10) + ["b"]=> + int(20) + ["c"]=> + array(0) { + } + } +} +object(Closure)#%d (1) { + ["this"]=> + object(Foo)#%d (0) { + } +} + diff --git a/Zend/tests/partial_application/variation_pass_001.phpt b/Zend/tests/partial_application/variation_pass_001.phpt new file mode 100644 index 0000000000000..98a92162ac52e --- /dev/null +++ b/Zend/tests/partial_application/variation_pass_001.phpt @@ -0,0 +1,14 @@ +--TEST-- +Partial application variation pass +--FILE-- +getMessage()); +} +?> +--EXPECT-- +too many arguments and or place holders for application of Foo::__construct, 1 given and a maximum of 0 expected diff --git a/Zend/tests/partial_application/variation_strict_001.phpt b/Zend/tests/partial_application/variation_strict_001.phpt new file mode 100644 index 0000000000000..f1aebb7d2d01e --- /dev/null +++ b/Zend/tests/partial_application/variation_strict_001.phpt @@ -0,0 +1,21 @@ +--TEST-- +Partial application variation: strict_types declared +--FILE-- +getMessage()); +} +?> +--EXPECT-- +foo(): Argument #1 ($int) must be of type int, string given + diff --git a/Zend/tests/partial_application/variation_variadics_001.phpt b/Zend/tests/partial_application/variation_variadics_001.phpt new file mode 100644 index 0000000000000..79deca98f2f9e --- /dev/null +++ b/Zend/tests/partial_application/variation_variadics_001.phpt @@ -0,0 +1,26 @@ +--TEST-- +Partial application variation variadics user +--FILE-- + +--EXPECTF-- +Function [ partial function foo ] { + @@ %s 6 - 6 + + - Parameters [1] { + Parameter #0 [ ...$b ] + } +} +int(10) +int(100) +int(1000) +int(10000) diff --git a/Zend/tests/partial_application/variation_variadics_002.phpt b/Zend/tests/partial_application/variation_variadics_002.phpt new file mode 100644 index 0000000000000..fba07a365b143 --- /dev/null +++ b/Zend/tests/partial_application/variation_variadics_002.phpt @@ -0,0 +1,19 @@ +--TEST-- +Partial application variation variadics internal +--FILE-- + +--EXPECTF-- +Function [ partial function sprintf ] { + + - Parameters [1] { + Parameter #0 [ mixed ...$values ] + } + - Return [ string ] +} +100 1000 10000 diff --git a/Zend/tests/partial_application/variation_variadics_003.phpt b/Zend/tests/partial_application/variation_variadics_003.phpt new file mode 100644 index 0000000000000..b70c4b77d69f3 --- /dev/null +++ b/Zend/tests/partial_application/variation_variadics_003.phpt @@ -0,0 +1,50 @@ +--TEST-- +Partial application variation variadics interactions +--FILE-- +getMessage()); +} + +try { + $foo = foo(?, ?, ?); // FAIL 2 expected, 3 given +} catch (Error $ex) { + printf("%s\n", $ex->getMessage()); +} + +function bar($a, $b, ...$c) { + var_dump(func_get_args()); +} + +$bar = bar(?, ?); + +try { + $bar(1, 2, 3); // FAIL 3 given, maximum 2 expected +} catch (Error $ex) { + printf("%s\n", $ex->getMessage()); +} + +$foo = foo(?, ?, ...); + +$foo(1, 2, 3); // OK +?> +--EXPECTF-- +too many arguments for application of foo, 3 given and a maximum of 2 expected, declared in %s on line %d +too many arguments and or place holders for application of foo, 3 given and a maximum of 2 expected, declared in %s on line %d +too many arguments for application of bar, 3 given and a maximum of 2 expected, declared in %s on line %d +array(3) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + int(3) +} diff --git a/Zend/tests/partial_application/variation_variadics_004.phpt b/Zend/tests/partial_application/variation_variadics_004.phpt new file mode 100644 index 0000000000000..6cda0fc81f5e7 --- /dev/null +++ b/Zend/tests/partial_application/variation_variadics_004.phpt @@ -0,0 +1,65 @@ +--TEST-- +Partial application variation variadics and optional args +--FILE-- + $day, "month" => $month, "year" => $year]; +} + +$foo = foo(..., year: 2006); + +var_dump($foo(2)); + +$foo = foo(..., month: 12); + +$bar = $foo(..., year: 2016); + +var_dump($foo(2)); + +var_dump($bar(2)); + +var_dump($foo()); + +var_dump($bar()); +?> +--EXPECTF-- +array(3) { + ["day"]=> + int(2) + ["month"]=> + int(1) + ["year"]=> + int(2006) +} +array(3) { + ["day"]=> + int(2) + ["month"]=> + int(12) + ["year"]=> + int(2005) +} +array(3) { + ["day"]=> + int(2) + ["month"]=> + int(12) + ["year"]=> + int(2016) +} +array(3) { + ["day"]=> + int(1) + ["month"]=> + int(1) + ["year"]=> + int(2005) +} +array(3) { + ["day"]=> + int(1) + ["month"]=> + int(12) + ["year"]=> + int(2005) +} diff --git a/Zend/tests/partial_application/variation_variadics_006.phpt b/Zend/tests/partial_application/variation_variadics_006.phpt new file mode 100644 index 0000000000000..d60de988db4d9 --- /dev/null +++ b/Zend/tests/partial_application/variation_variadics_006.phpt @@ -0,0 +1,18 @@ +--TEST-- +Partial application variation named may overwrite variadic place holder +--FILE-- + +--EXPECTF-- +array(1) { + [0]=> + string(1) "a" +} + diff --git a/Zend/zend.c b/Zend/zend.c index 63f90c4d4c215..a03ed458453d1 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -35,6 +35,7 @@ #include "zend_attributes.h" #include "zend_observer.h" #include "zend_fibers.h" +#include "zend_partial.h" #include "Optimizer/zend_optimizer.h" static size_t global_map_ptr_last = 0; @@ -1010,6 +1011,8 @@ void zend_startup(zend_utility_functions *utility_functions) /* {{{ */ tsrm_set_new_thread_end_handler(zend_new_thread_end_handler); tsrm_set_shutdown_handler(zend_interned_strings_dtor); #endif + + zend_partial_startup(); } /* }}} */ diff --git a/Zend/zend_ast.c b/Zend/zend_ast.c index e222e4bd74019..337c362c471fe 100644 --- a/Zend/zend_ast.c +++ b/Zend/zend_ast.c @@ -1728,6 +1728,13 @@ static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int prio EMPTY_SWITCH_DEFAULT_CASE(); } break; + case ZEND_AST_PLACEHOLDER_ARG: + if (ast->attr == _IS_PLACEHOLDER_ARG) { + APPEND_STR("?"); + } else if (ast->attr == _IS_PLACEHOLDER_VARIADIC) { + APPEND_STR("..."); + } + break; /* 1 child node */ case ZEND_AST_VAR: diff --git a/Zend/zend_ast.h b/Zend/zend_ast.h index 0e3468ebde110..3fadd27c02999 100644 --- a/Zend/zend_ast.h +++ b/Zend/zend_ast.h @@ -70,6 +70,7 @@ enum _zend_ast_kind { ZEND_AST_MAGIC_CONST = 0 << ZEND_AST_NUM_CHILDREN_SHIFT, ZEND_AST_TYPE, ZEND_AST_CONSTANT_CLASS, + ZEND_AST_PLACEHOLDER_ARG, /* 1 child node */ ZEND_AST_VAR = 1 << ZEND_AST_NUM_CHILDREN_SHIFT, diff --git a/Zend/zend_closures.c b/Zend/zend_closures.c index 5ae122b7f94ab..f352eac4e4df9 100644 --- a/Zend/zend_closures.c +++ b/Zend/zend_closures.c @@ -40,6 +40,8 @@ typedef struct _zend_closure { ZEND_API zend_class_entry *zend_ce_closure; static zend_object_handlers closure_handlers; +static zval zend_closure_no_this; + ZEND_METHOD(Closure, __invoke) /* {{{ */ { zend_function *func = EX(func); @@ -55,9 +57,11 @@ ZEND_METHOD(Closure, __invoke) /* {{{ */ RETVAL_FALSE; } - /* destruct the function also, then - we have allocated it in get_method */ - zend_string_release_ex(func->internal_function.function_name, 0); - efree(func); + if (!(func->common.fn_flags & ZEND_ACC_TRAMPOLINE_PERMANENT)) { + /* destruct the function also, then - we have allocated it in get_method */ + zend_string_release_ex(func->internal_function.function_name, 0); + efree(func); + } #if ZEND_DEBUG execute_data->func = NULL; #endif @@ -69,6 +73,12 @@ static bool zend_valid_closure_binding( { zend_function *func = &closure->func; bool is_fake_closure = (func->common.fn_flags & ZEND_ACC_FAKE_CLOSURE) != 0; + + if (func->common.fn_flags & ZEND_ACC_PARTIAL) { + zend_error(E_WARNING, "Cannot bind an instance to a partial Closure"); + return 0; + } + if (newthis) { if (func->common.fn_flags & ZEND_ACC_STATIC) { zend_error(E_WARNING, "Cannot bind an instance to a static closure"); @@ -423,6 +433,12 @@ ZEND_API const zend_function *zend_get_closure_method_def(zend_object *obj) /* { ZEND_API zval* zend_get_closure_this_ptr(zval *obj) /* {{{ */ { zend_closure *closure = (zend_closure *)Z_OBJ_P(obj); + + if (UNEXPECTED(Z_TYPE(closure->this_ptr) != IS_OBJECT)) { + /* zend_partial This may refer to a type */ + return &zend_closure_no_this; + } + return &closure->this_ptr; } /* }}} */ @@ -501,7 +517,7 @@ int zend_closure_get_closure(zend_object *obj, zend_class_entry **ce_ptr, zend_f /* }}} */ /* *is_temp is int due to Object Handler API */ -static HashTable *zend_closure_get_debug_info(zend_object *object, int *is_temp) /* {{{ */ +HashTable *zend_closure_get_debug_info(zend_object *object, int *is_temp) /* {{{ */ { zend_closure *closure = (zend_closure *)object; zval val; @@ -542,7 +558,7 @@ static HashTable *zend_closure_get_debug_info(zend_object *object, int *is_temp) } } - if (Z_TYPE(closure->this_ptr) != IS_UNDEF) { + if (Z_TYPE(closure->this_ptr) == IS_OBJECT) { Z_ADDREF(closure->this_ptr); zend_hash_update(debug_info, ZSTR_KNOWN(ZEND_STR_THIS), &closure->this_ptr); } @@ -624,6 +640,8 @@ void zend_register_closure_ce(void) /* {{{ */ closure_handlers.get_debug_info = zend_closure_get_debug_info; closure_handlers.get_closure = zend_closure_get_closure; closure_handlers.get_gc = zend_closure_get_gc; + + ZVAL_UNDEF(&zend_closure_no_this); } /* }}} */ diff --git a/Zend/zend_closures.h b/Zend/zend_closures.h index 5b990cc0f9b60..f66b095fbc95f 100644 --- a/Zend/zend_closures.h +++ b/Zend/zend_closures.h @@ -29,6 +29,7 @@ BEGIN_EXTERN_C() void zend_register_closure_ce(void); void zend_closure_bind_var(zval *closure_zv, zend_string *var_name, zval *var); void zend_closure_bind_var_ex(zval *closure_zv, uint32_t offset, zval *val); +HashTable *zend_closure_get_debug_info(zend_object *object, int *is_temp); extern ZEND_API zend_class_entry *zend_ce_closure; diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index dade906f4b891..f95e521566020 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -3445,11 +3445,12 @@ static uint32_t zend_get_arg_num(zend_function *fn, zend_string *arg_name) { } uint32_t zend_compile_args( - zend_ast *ast, zend_function *fbc, bool *may_have_extra_named_args) /* {{{ */ + zend_ast *ast, zend_function *fbc, bool *may_have_extra_named_args, bool *is_call_partial) /* {{{ */ { zend_ast_list *args = zend_ast_get_list(ast); uint32_t i; bool uses_arg_unpack = 0; + bool uses_variadic_placeholder = 0; uint32_t arg_count = 0; /* number of arguments not including unpacks */ /* Whether named arguments are used syntactically, to enforce language level limitations. @@ -3459,6 +3460,8 @@ uint32_t zend_compile_args( bool may_have_undef = 0; /* Whether there may be any extra named arguments collected into a variadic. */ *may_have_extra_named_args = 0; + /* Whether this is a partial call */ + *is_call_partial = false; for (i = 0; i < args->children; ++i) { zend_ast *arg = args->child[i]; @@ -3475,6 +3478,11 @@ uint32_t zend_compile_args( "Cannot use argument unpacking after named arguments"); } + if (*is_call_partial) { + zend_error_noreturn(E_COMPILE_ERROR, + "Cannot combine partial application and unpacking"); + } + uses_arg_unpack = 1; fbc = NULL; @@ -3491,6 +3499,47 @@ uint32_t zend_compile_args( continue; } + if (arg->kind == ZEND_AST_PLACEHOLDER_ARG) { + if (uses_arg_unpack) { + zend_error_noreturn(E_COMPILE_ERROR, + "Cannot combine partial application and unpacking"); + } + + if (arg->attr == _IS_PLACEHOLDER_VARIADIC) { + if (uses_named_args) { + zend_error_noreturn(E_COMPILE_ERROR, + "Named arguments must come after all place holders"); + } + + if (uses_variadic_placeholder) { + zend_error_noreturn(E_COMPILE_ERROR, + "Variadic place holder may only appear once"); + } + + uses_variadic_placeholder = 1; + } else if (arg->attr == _IS_PLACEHOLDER_ARG) { + if (uses_named_args) { + zend_error_noreturn(E_COMPILE_ERROR, + "Named arguments must come after all place holders"); + } + + if (uses_variadic_placeholder) { + zend_error_noreturn(E_COMPILE_ERROR, + "Only named arguments may follow variadic place holder"); + } + } + + fbc = NULL; + + opline = zend_emit_op(NULL, ZEND_SEND_PLACEHOLDER, NULL, NULL); + opline->op1.num = arg->attr; + opline->op2.num = arg_num; + + *is_call_partial = true; + arg_count++; + continue; + } + if (arg->kind == ZEND_AST_NAMED_ARG) { uses_named_args = 1; arg_name = zval_make_interned_string(zend_ast_get_zval(arg->child[0])); @@ -3525,6 +3574,11 @@ uint32_t zend_compile_args( "Cannot use positional argument after named argument"); } + if (uses_variadic_placeholder) { + zend_error_noreturn(E_COMPILE_ERROR, + "Only named arguments may follow variadic place holder"); + } + arg_count++; } @@ -3635,8 +3689,12 @@ uint32_t zend_compile_args( } } - if (may_have_undef) { - zend_emit_op(NULL, ZEND_CHECK_UNDEF_ARGS, NULL, NULL); + if (!*is_call_partial) { + if (may_have_undef) { + zend_emit_op(NULL, ZEND_CHECK_UNDEF_ARGS, NULL, NULL); + } + } else { + zend_emit_op(NULL, ZEND_CHECK_PARTIAL_ARGS, NULL, NULL); } return arg_count; @@ -3669,14 +3727,40 @@ ZEND_API zend_uchar zend_get_call_op(const zend_op *init_op, zend_function *fbc) } /* }}} */ +void zend_compile_call_partial(znode *result, uint32_t arg_count, bool may_have_extra_named_args, uint32_t opnum_init, zend_function *fbc) { /* {{{ */ + zend_op *opline = &CG(active_op_array)->opcodes[opnum_init]; + znode op1; + + opline->extended_value = arg_count; + + if (opline->opcode == ZEND_INIT_FCALL) { + opline->op1.num = zend_vm_calc_used_stack(arg_count, fbc); + } else if (opline->opcode == ZEND_NEW) { + GET_NODE(&op1, opline->result); + } + + opline = zend_emit_op(result, ZEND_DO_FCALL_PARTIAL, + (opline->opcode == ZEND_NEW) ? &op1 : NULL, NULL); + + if (may_have_extra_named_args) { + opline->extended_value = ZEND_FCALL_MAY_HAVE_EXTRA_NAMED_PARAMS; + } +} /* }}} */ + void zend_compile_call_common(znode *result, zend_ast *args_ast, zend_function *fbc) /* {{{ */ { zend_op *opline; uint32_t opnum_init = get_next_op_number() - 1; uint32_t arg_count; bool may_have_extra_named_args; + bool is_partial_call; + + arg_count = zend_compile_args(args_ast, fbc, &may_have_extra_named_args, &is_partial_call); - arg_count = zend_compile_args(args_ast, fbc, &may_have_extra_named_args); + if (is_partial_call) { + zend_compile_call_partial(result, arg_count, may_have_extra_named_args, opnum_init, fbc); + return; + } zend_do_extended_fcall_begin(); @@ -3691,6 +3775,7 @@ void zend_compile_call_common(znode *result, zend_ast *args_ast, zend_function * if (may_have_extra_named_args) { opline->extended_value = ZEND_FCALL_MAY_HAVE_EXTRA_NAMED_PARAMS; } + zend_do_extended_fcall_end(); } /* }}} */ @@ -3755,12 +3840,14 @@ void zend_compile_dynamic_call(znode *result, znode *name_node, zend_ast *args_a } /* }}} */ -static inline bool zend_args_contain_unpack_or_named(zend_ast_list *args) /* {{{ */ +static inline bool zend_args_contain_unpack_or_named_or_partial(zend_ast_list *args) /* {{{ */ { uint32_t i; for (i = 0; i < args->children; ++i) { zend_ast *arg = args->child[i]; - if (arg->kind == ZEND_AST_UNPACK || arg->kind == ZEND_AST_NAMED_ARG) { + if (arg->kind == ZEND_AST_UNPACK || + arg->kind == ZEND_AST_NAMED_ARG || + arg->kind == ZEND_AST_PLACEHOLDER_ARG) { return 1; } } @@ -3987,7 +4074,7 @@ zend_result zend_compile_func_cufa(znode *result, zend_ast_list *args, zend_stri zend_string *name = zend_resolve_function_name(orig_name, args->child[1]->child[0]->attr, &is_fully_qualified); if (zend_string_equals_literal_ci(name, "array_slice") - && !zend_args_contain_unpack_or_named(list) + && !zend_args_contain_unpack_or_named_or_partial(list) && list->children == 3 && list->child[1]->kind == ZEND_AST_ZVAL) { zval *zv = zend_ast_get_zval(list->child[1]); @@ -4323,7 +4410,7 @@ zend_result zend_try_compile_special_func(znode *result, zend_string *lcname, ze return FAILURE; } - if (zend_args_contain_unpack_or_named(args)) { + if (zend_args_contain_unpack_or_named_or_partial(args)) { return FAILURE; } diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 76405a3689dc9..902dd766b36e4 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -238,7 +238,7 @@ typedef struct _zend_oparray_context { /* or IS_CONSTANT_VISITED_MARK | | | */ #define ZEND_CLASS_CONST_IS_CASE (1 << 6) /* | | | X */ /* | | | */ -/* Class Flags (unused: 29...) | | | */ +/* Class Flags (unused: 30...) | | | */ /* =========== | | | */ /* | | | */ /* Special class types | | | */ @@ -357,6 +357,12 @@ typedef struct _zend_oparray_context { /* method flag used by Closure::__invoke() (int only) | | | */ #define ZEND_ACC_USER_ARG_INFO (1 << 26) /* | X | | */ /* | | | */ +/* flag used by partial application (int only) | | | */ +#define ZEND_ACC_PARTIAL (1 << 27) /* | X | | */ +/* | | | */ +/* trampoline is permanent | | | */ +#define ZEND_ACC_TRAMPOLINE_PERMANENT (1 << 29) /* | X | | */ +/* | | | */ /* op_array uses strict mode types | | | */ #define ZEND_ACC_STRICT_TYPES (1U << 31) /* | X | | */ @@ -555,6 +561,7 @@ struct _zend_execute_data { #define ZEND_CALL_OBSERVED (1 << 28) /* "fcall_begin" observer handler may set this flag */ /* to prevent optimization in RETURN handler and */ /* keep all local variables for "fcall_end" handler */ +#define ZEND_CALL_VARIADIC_PLACEHOLDER (1<<29) #define ZEND_CALL_SEND_ARG_BY_REF (1u << 31) #define ZEND_CALL_NESTED_FUNCTION (ZEND_CALL_FUNCTION | ZEND_CALL_NESTED) diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 748967cf5e5d2..cf2be7434e75f 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -34,6 +34,7 @@ #include "zend_exceptions.h" #include "zend_interfaces.h" #include "zend_closures.h" +#include "zend_partial.h" #include "zend_generators.h" #include "zend_vm.h" #include "zend_dtrace.h" @@ -1157,8 +1158,9 @@ static zend_never_inline ZEND_ATTRIBUTE_UNUSED bool zend_verify_internal_arg_typ * trust that arginfo matches what is enforced by zend_parse_parameters. */ static zend_always_inline bool zend_internal_call_should_throw(zend_function *fbc, zend_execute_data *call) { - if (fbc->internal_function.handler == ZEND_FN(pass)) { - /* Be lenient about the special pass function. */ + if (fbc->internal_function.handler == ZEND_FN(pass) || + fbc->internal_function.handler == zend_partial_call_magic) { + /* Be lenient about the special pass functions. */ return 0; } @@ -4477,8 +4479,8 @@ zval * ZEND_FASTCALL zend_handle_named_arg( arg = zend_hash_add_empty_element(call->extra_named_params, arg_name); if (!arg) { - zend_throw_error(NULL, "Named parameter $%s overwrites previous argument", - ZSTR_VAL(arg_name)); + zend_throw_error(NULL, "Named parameter $%s overwrites previous %s", + ZSTR_VAL(arg_name), Z_TYPE_P(arg) == _IS_PLACEHOLDER_ARG ? "place holder" : "argument"); return NULL; } *arg_num_ptr = arg_offset + 1; @@ -4507,9 +4509,14 @@ zval * ZEND_FASTCALL zend_handle_named_arg( } } else { arg = ZEND_CALL_VAR_NUM(call, arg_offset); + + if (UNEXPECTED(Z_TYPE_P(arg) == _IS_PLACEHOLDER_VARIADIC)) { + ZVAL_UNDEF(arg); + } + if (UNEXPECTED(!Z_ISUNDEF_P(arg))) { - zend_throw_error(NULL, "Named parameter $%s overwrites previous argument", - ZSTR_VAL(arg_name)); + zend_throw_error(NULL, "Named parameter $%s overwrites previous %s", + ZSTR_VAL(arg_name), Z_TYPE_P(arg) == _IS_PLACEHOLDER_ARG ? "place holder" : "argument"); return NULL; } } diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index e783a7d9aa1e7..5d0cd95313024 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -840,6 +840,10 @@ argument: expr { $$ = $1; } | identifier ':' expr { $$ = zend_ast_create(ZEND_AST_NAMED_ARG, $1, $3); } + | '?' { $$ = zend_ast_create(ZEND_AST_PLACEHOLDER_ARG); + $$->attr = _IS_PLACEHOLDER_ARG; } + | T_ELLIPSIS { $$ = zend_ast_create(ZEND_AST_PLACEHOLDER_ARG); + $$->attr = _IS_PLACEHOLDER_VARIADIC; } | T_ELLIPSIS expr { $$ = zend_ast_create(ZEND_AST_UNPACK, $2); } ; diff --git a/Zend/zend_object_handlers.h b/Zend/zend_object_handlers.h index 53eef829282ce..d680eadff5620 100644 --- a/Zend/zend_object_handlers.h +++ b/Zend/zend_object_handlers.h @@ -256,7 +256,7 @@ ZEND_API HashTable *zend_get_properties_for(zval *obj, zend_prop_purpose purpose #define zend_free_trampoline(func) do { \ if ((func) == &EG(trampoline)) { \ EG(trampoline).common.function_name = NULL; \ - } else { \ + } else if (!(func->common.fn_flags & ZEND_ACC_TRAMPOLINE_PERMANENT)) { \ efree(func); \ } \ } while (0) diff --git a/Zend/zend_partial.c b/Zend/zend_partial.c new file mode 100644 index 0000000000000..e268ffb1684a4 --- /dev/null +++ b/Zend/zend_partial.c @@ -0,0 +1,876 @@ +/* + +----------------------------------------------------------------------+ + | Zend Engine | + +----------------------------------------------------------------------+ + | Copyright (c) Zend Technologies Ltd. (http://www.zend.com) | + +----------------------------------------------------------------------+ + | This source file is subject to version 2.00 of the Zend license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.zend.com/license/2_00.txt. | + | If you did not receive a copy of the Zend license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@zend.com so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: krakjoe | + +----------------------------------------------------------------------+ +*/ +#include "zend.h" +#include "zend_API.h" +#include "zend_interfaces.h" +#include "zend_closures.h" +#include "zend_partial.h" + +typedef struct _zend_partial { + zend_object std; + zend_function prototype; + zval This; + zend_function func; + zend_function trampoline; + uint32_t argc; + zval *argv; + zend_array *named; +} zend_partial; + +static zend_object_handlers zend_partial_handlers; + +static zend_arg_info zend_call_magic_arginfo[1]; + +#define Z_IS_PLACEHOLDER_ARG_P(p) (Z_TYPE_P(p) == _IS_PLACEHOLDER_ARG) +#define Z_IS_PLACEHOLDER_VARIADIC_P(p) (Z_TYPE_P(p) == _IS_PLACEHOLDER_VARIADIC) + +#define Z_IS_PLACEHOLDER_P(p) \ + (Z_IS_PLACEHOLDER_ARG_P(p) || Z_IS_PLACEHOLDER_VARIADIC_P(p)) + +#define Z_IS_NOT_PLACEHOLDER_P(p) \ + (!Z_IS_PLACEHOLDER_ARG_P(p) && !Z_IS_PLACEHOLDER_VARIADIC_P(p)) + +#define ZEND_PARTIAL_IS_CALL_TRAMPOLINE(func) \ + UNEXPECTED(((func)->type == ZEND_USER_FUNCTION) && ((func)->op_array.opcodes == &EG(call_trampoline_op))) + +#define ZEND_PARTIAL_FUNC_SIZE(func) \ + (((func)->type == ZEND_INTERNAL_FUNCTION) ? sizeof(zend_internal_function) : sizeof(zend_op_array)) + +#define ZEND_PARTIAL_FUNC_FLAG(func, flags) \ + ((func)->common.fn_flags & flags) + +#define ZEND_PARTIAL_FUNC_DEL(func, flag) \ + ((func)->common.fn_flags &= ~flag) + +#define ZEND_PARTIAL_FUNC_ADD(func, flag) \ + ((func)->common.fn_flags |= flag) + +#define ZEND_PARTIAL_CALL_FLAG(partial, flag) \ + (ZEND_CALL_INFO(partial) & flag) + +static zend_always_inline uint32_t zend_partial_signature_size(zend_partial *partial) { + uint32_t count = partial->func.common.num_args + partial->argc; + + if (ZEND_PARTIAL_FUNC_FLAG(&partial->func, ZEND_ACC_HAS_RETURN_TYPE)) { + count++; + } + + if (ZEND_PARTIAL_CALL_FLAG(partial, ZEND_APPLY_VARIADIC)|| + ZEND_PARTIAL_FUNC_FLAG(&partial->func, ZEND_ACC_VARIADIC)) { + count++; + } + + return count * sizeof(zend_arg_info); +} + +#define ZEND_PARTIAL_SIGNATURE_SIZE(partial) zend_partial_signature_size(partial) + +static zend_always_inline zend_function* zend_partial_signature_create(zend_partial *partial, zend_function *prototype) { + zend_arg_info *signature = emalloc(ZEND_PARTIAL_SIGNATURE_SIZE(partial)), *info = signature; + + memcpy(&partial->prototype, prototype, ZEND_PARTIAL_FUNC_SIZE(prototype)); + + if (ZEND_PARTIAL_FUNC_FLAG(prototype, ZEND_ACC_HAS_RETURN_TYPE)) { + memcpy(info, + prototype->common.arg_info - 1, sizeof(zend_arg_info)); + info++; + } + + uint32_t offset = 0, num = 0, required = 0, limit = partial->argc; + + if (ZEND_PARTIAL_CALL_FLAG(partial, ZEND_APPLY_VARIADIC)) { + limit++; + } + + ZEND_PARTIAL_FUNC_DEL(&partial->prototype, ZEND_ACC_VARIADIC); + + while (offset < limit) { + zval *arg = &partial->argv[offset]; + + if (Z_IS_PLACEHOLDER_ARG_P(arg)) { + if (offset < prototype->common.num_args) { + num++; + required++; + memcpy(info, + &prototype->common.arg_info[offset], + sizeof(zend_arg_info)); + ZEND_TYPE_FULL_MASK(info->type) &= ~_ZEND_IS_VARIADIC_BIT; + info++; + } else if (ZEND_PARTIAL_FUNC_FLAG(prototype, ZEND_ACC_VARIADIC)) { + num++; + required++; + if (ZEND_PARTIAL_IS_CALL_TRAMPOLINE(prototype)) { + memcpy(info, zend_call_magic_arginfo, sizeof(zend_arg_info)); + } else { + memcpy(info, + prototype->common.arg_info + prototype->common.num_args, + sizeof(zend_arg_info)); + } + + ZEND_TYPE_FULL_MASK(info->type) &= ~_ZEND_IS_VARIADIC_BIT; + info++; + } else { + ZEND_ASSERT(0 && "argument out of range"); + } + } else if (Z_IS_PLACEHOLDER_VARIADIC_P(arg)) { + if (offset < prototype->common.num_args) { + while (offset < prototype->common.num_args) { + if ((offset < partial->argc) && + !Z_IS_PLACEHOLDER_P(&partial->argv[offset]) && + !Z_ISUNDEF(partial->argv[offset])) { + offset++; + continue; + } + + num++; + memcpy(info, + &prototype->common.arg_info[offset], + sizeof(zend_arg_info)); + ZEND_TYPE_FULL_MASK(info->type) &= ~_ZEND_IS_VARIADIC_BIT; + info++; + offset++; + } + + if (ZEND_PARTIAL_FUNC_FLAG(prototype, ZEND_ACC_VARIADIC)) { + if (ZEND_PARTIAL_IS_CALL_TRAMPOLINE(prototype)) { + memcpy(info, zend_call_magic_arginfo, sizeof(zend_arg_info)); + } else { + memcpy(info, + prototype->common.arg_info + prototype->common.num_args, + sizeof(zend_arg_info)); + } + num++; + } + + if (ZEND_TYPE_FULL_MASK(info->type) & _ZEND_IS_VARIADIC_BIT) { + ZEND_PARTIAL_FUNC_ADD(&partial->prototype, ZEND_ACC_VARIADIC); + } + break; + } else if (ZEND_PARTIAL_FUNC_FLAG(prototype, ZEND_ACC_VARIADIC)) { + ZEND_PARTIAL_FUNC_ADD(&partial->prototype, ZEND_ACC_VARIADIC); + num++; + if (ZEND_PARTIAL_IS_CALL_TRAMPOLINE(prototype)) { + memcpy(info, zend_call_magic_arginfo, sizeof(zend_arg_info)); + } else { + memcpy(info, + prototype->common.arg_info + prototype->common.num_args, + sizeof(zend_arg_info)); + } + info++; + } + } + + offset++; + } + + if (ZEND_PARTIAL_FUNC_FLAG(&partial->prototype, ZEND_ACC_VARIADIC)) { + num--; + } + + partial->prototype.common.num_args = num; + partial->prototype.common.required_num_args = required; + partial->prototype.common.arg_info = signature; + + if (ZEND_PARTIAL_FUNC_FLAG(&partial->prototype, ZEND_ACC_HAS_RETURN_TYPE)) { + partial->prototype.common.arg_info++; + } + + ZEND_PARTIAL_FUNC_ADD(&partial->prototype, ZEND_ACC_PARTIAL); + + partial->prototype.common.prototype = &partial->func; + + if (prototype->type == ZEND_INTERNAL_FUNCTION) { + return &partial->prototype; + } + + zend_string *filename = zend_get_executed_filename_ex(); + + if (!filename) { + if (partial->prototype.op_array.filename) { + zend_string_addref(partial->prototype.op_array.filename); + } + return &partial->prototype; + } + + partial->prototype.op_array.filename = zend_string_copy(filename); + partial->prototype.op_array.line_start = + partial->prototype.op_array.line_end = zend_get_executed_lineno(); + + return &partial->prototype; +} + +static zend_always_inline zend_partial* zend_partial_fetch(zval *This) { + if (!This || Z_TYPE_P(This) != IS_OBJECT) { + return NULL; + } + + if (UNEXPECTED(!instanceof_function(Z_OBJCE_P(This), zend_ce_closure))) { + return NULL; + } + + zend_partial *ptr = (zend_partial*) Z_OBJ_P(This); + + if (!ZEND_PARTIAL_FUNC_FLAG(&ptr->prototype, ZEND_ACC_PARTIAL)) { + return NULL; + } + + return ptr; +} + +static zend_always_inline void zend_partial_trampoline_create(zend_partial *partial, zend_function *trampoline) +{ + const uint32_t keep_flags = + ZEND_ACC_RETURN_REFERENCE | ZEND_ACC_VARIADIC | ZEND_ACC_HAS_RETURN_TYPE | ZEND_ACC_STRICT_TYPES; + + trampoline->common = partial->prototype.common; + trampoline->type = ZEND_INTERNAL_FUNCTION; + trampoline->internal_function.fn_flags = + ZEND_ACC_PUBLIC | ZEND_ACC_CALL_VIA_HANDLER | ZEND_ACC_TRAMPOLINE_PERMANENT | (partial->func.common.fn_flags & keep_flags); + if (partial->func.type != ZEND_INTERNAL_FUNCTION || (partial->func.common.fn_flags & ZEND_ACC_USER_ARG_INFO)) { + trampoline->internal_function.fn_flags |= + ZEND_ACC_USER_ARG_INFO; + } + trampoline->internal_function.handler = zend_partial_call_magic; + trampoline->internal_function.module = 0; + trampoline->internal_function.scope = zend_ce_closure; + trampoline->internal_function.function_name = ZSTR_KNOWN(ZEND_STR_MAGIC_INVOKE); +} + +static zend_always_inline zend_object* zend_partial_new(zend_class_entry *type, uint32_t info) { + zend_partial *partial = ecalloc(1, sizeof(zend_partial)); + + zend_object_std_init(&partial->std, type); + + partial->std.handlers = &zend_partial_handlers; + + ZEND_ADD_CALL_FLAG(partial, info); + + return (zend_object*) partial; +} + +static zend_always_inline void zend_partial_debug_add(zend_function *function, HashTable *ht, zend_arg_info *info, zval *value) { + if (function->type == ZEND_USER_FUNCTION || ZEND_PARTIAL_FUNC_FLAG(function, ZEND_ACC_USER_ARG_INFO)) { + zend_hash_add(ht, info->name, value); + } else { + zend_internal_arg_info *internal = (zend_internal_arg_info*) info; + + zend_hash_str_add(ht, internal->name, strlen(internal->name), value); + } +} + +static zend_always_inline void zend_partial_debug_fill(zend_partial *partial, HashTable *ht) { + zval *arg = partial->argv, + *aend = arg + partial->argc; + zend_arg_info *info = partial->func.common.arg_info, + *iend = info + partial->func.common.num_args; + + while (info < iend) { + zval param; + + ZVAL_NULL(¶m); + + if (arg < aend) { + if (Z_IS_NOT_PLACEHOLDER_P(arg)) { + ZVAL_COPY_VALUE(¶m, arg); + } + + arg++; + } + + zend_partial_debug_add(&partial->func, ht, info, ¶m); + + if (Z_OPT_REFCOUNTED(param)) { + Z_ADDREF(param); + } + info++; + } + + if (ZEND_PARTIAL_FUNC_FLAG(&partial->func, ZEND_ACC_VARIADIC)) { + zval variadics; + + array_init(&variadics); + + zend_partial_debug_add(&partial->func, ht, info, &variadics); + + while (arg < aend) { + if (Z_IS_NOT_PLACEHOLDER_P(arg)) { + zend_hash_next_index_insert(Z_ARRVAL(variadics), arg); + + if (Z_OPT_REFCOUNTED_P(arg)) { + Z_ADDREF_P(arg); + } + } + + arg++; + } + + if (partial->named) { + zend_hash_merge(Z_ARRVAL(variadics), partial->named, zval_copy_ctor, true); + } + } +} + +static HashTable *zend_partial_debug(zend_object *object, int *is_temp) { + zend_partial *partial = (zend_partial*) object; + zval args; + HashTable *ht; + + ht = zend_closure_get_debug_info(object, is_temp); + + array_init(&args); + zend_hash_update(ht, ZSTR_KNOWN(ZEND_STR_ARGS), &args); + + zend_partial_debug_fill(partial, Z_ARRVAL(args)); + + return ht; +} + +static HashTable *zend_partial_get_gc(zend_object *obj, zval **table, int *n) +{ + zend_partial *partial = (zend_partial *)obj; + + *table = Z_TYPE(partial->This) == IS_OBJECT ? &partial->This : NULL; + *n = Z_TYPE(partial->This) == IS_OBJECT ? 1 : 0; + + return NULL; +} + +static zend_function *zend_partial_get_method(zend_object **object, zend_string *method, const zval *key) /* {{{ */ +{ + if (zend_string_equals_literal_ci(method, ZEND_INVOKE_FUNC_NAME)) { + zend_partial *partial = (zend_partial*) *object; + + return &partial->trampoline; + } + + return zend_std_get_method(object, method, key); +} +/* }}} */ + +static int zend_partial_get_trampoline(zend_object *obj, zend_class_entry **ce_ptr, zend_function **fptr_ptr, zend_object **obj_ptr, bool check_only) +{ + zend_partial *partial = (zend_partial*) obj; + + *fptr_ptr = &partial->trampoline; + *obj_ptr = (zend_object*) &partial->std; + + return SUCCESS; +} + +static void zend_partial_free(zend_object *object) { + zend_partial *partial = (zend_partial*) object; + + zval *arg = partial->argv, + *end = arg + partial->argc; + + while (arg < end) { + if (Z_OPT_REFCOUNTED_P(arg)) { + zval_ptr_dtor(arg); + } + arg++; + } + + efree(partial->argv); + + if (partial->named) { + zend_array_release(partial->named); + } + + zend_arg_info *info = partial->prototype.common.arg_info; + + if (ZEND_PARTIAL_FUNC_FLAG(&partial->func, ZEND_ACC_HAS_RETURN_TYPE)) { + info--; + } + + efree(info); + + if (partial->func.type == ZEND_USER_FUNCTION) { + if (partial->prototype.op_array.filename) { + zend_string_release(partial->prototype.op_array.filename); + } + destroy_zend_function(&partial->func); + } + + if (Z_TYPE(partial->This) == IS_OBJECT) { + zval_ptr_dtor(&partial->This); + } + + zend_object_std_dtor(object); +} + +void zend_partial_startup(void) { + memcpy(&zend_partial_handlers, + &std_object_handlers, sizeof(zend_object_handlers)); + + zend_partial_handlers.free_obj = zend_partial_free; + zend_partial_handlers.get_debug_info = zend_partial_debug; + zend_partial_handlers.get_gc = zend_partial_get_gc; + zend_partial_handlers.get_closure = zend_partial_get_trampoline; + zend_partial_handlers.get_method = zend_partial_get_method; + + memset(&zend_call_magic_arginfo, 0, sizeof(zend_arg_info) * 1); + + zend_call_magic_arginfo[0].name = zend_string_init_interned("args", sizeof("args")-1, 1); + zend_call_magic_arginfo[0].type = (zend_type) ZEND_TYPE_INIT_NONE(_ZEND_IS_VARIADIC_BIT); +} + +static zend_always_inline zend_string* zend_partial_function_name(zend_function *function) { + if (function->type == ZEND_INTERNAL_FUNCTION) { + if (function->internal_function.handler == zend_pass_function.handler) { + return zend_strpprintf(0, "__construct"); + } + } + return zend_string_copy(function->common.function_name); +} + +static zend_always_inline zend_string* zend_partial_scope_name(zend_execute_data *execute_data, zend_function *function) { + if (function->type == ZEND_INTERNAL_FUNCTION) { + if (function->internal_function.handler == zend_pass_function.handler) { + if (Z_OBJ(EX(This))) { + return Z_OBJCE(EX(This))->name; + } + } + } + + if (function->common.scope) { + return function->common.scope->name; + } + + return NULL; +} + +static zend_always_inline zend_string* zend_partial_symbol_name(zend_execute_data *call, zend_function *function) { + zend_string *name = zend_partial_function_name(function), + *scope = zend_partial_scope_name(call, function), + *symbol; + + if (scope) { + symbol = zend_strpprintf(0, "%s::%s", ZSTR_VAL(scope), ZSTR_VAL(name)); + } else { + symbol = zend_strpprintf(0, "%s", ZSTR_VAL(name)); + } + + zend_string_release(name); + return symbol; +} + +static zend_always_inline void zend_partial_prototype_underflow(zend_function *function, zend_string *symbol, uint32_t args, uint32_t expected, bool variadic) { + char *limit = variadic ? "at least" : "exactly"; + + if (function->type == ZEND_USER_FUNCTION) { + zend_throw_error(NULL, + "not enough arguments for application of %s, " + "%d given and %s %d expected, declared in %s on line %d", + ZSTR_VAL(symbol), args, limit, expected, + ZSTR_VAL(function->op_array.filename), function->op_array.line_start); + } else { + zend_throw_error(NULL, + "not enough arguments for application of %s, %d given and %s %d expected", + ZSTR_VAL(symbol), args, limit, expected); + } +} + +static zend_always_inline void zend_partial_prototype_overflow(zend_function *function, zend_string *symbol, uint32_t args, uint32_t expected) { + if (function->type == ZEND_USER_FUNCTION) { + zend_throw_error(NULL, + "too many arguments for application of %s, " + "%d given and a maximum of %d expected, declared in %s on line %d", + ZSTR_VAL(symbol), args, expected, + ZSTR_VAL(function->op_array.filename), function->op_array.line_start); + } else { + zend_throw_error(NULL, + "not enough arguments for application of %s, %d given and a maximum of %d expected", + ZSTR_VAL(symbol), args, expected); + } +} + +static zend_always_inline void zend_partial_args_underflow(zend_function *function, zend_string *symbol, uint32_t args, uint32_t expected, bool calling, bool prototype) { + const char *what = calling ? + "arguments" : "arguments and or place holders"; + const char *from = prototype ? + "application" : "implementation"; + const char *limit = function->common.num_args <= function->common.required_num_args ? + "exactly" : "at least"; + + if (function->type == ZEND_USER_FUNCTION) { + zend_throw_error(NULL, + "not enough %s for %s of %s, " + "%d given and %s %d expected, declared in %s on line %d", + what, from, ZSTR_VAL(symbol), args, limit, expected, + ZSTR_VAL(function->op_array.filename), function->op_array.line_start); + } else { + zend_throw_error(NULL, + "not enough %s for %s of %s, %d given and %s %d expected", + what, from, ZSTR_VAL(symbol), args, limit, expected); + } +} + +static zend_always_inline void zend_partial_args_overflow(zend_function *function, zend_string *symbol, uint32_t args, uint32_t expected, bool calling, bool prototype) { + const char *what = calling ? + "arguments" : "arguments and or place holders"; + const char *from = prototype ? + "application" : "implementation"; + + if (function->type == ZEND_USER_FUNCTION) { + zend_throw_error(NULL, + "too many %s for %s of %s, " + "%d given and a maximum of %d expected, declared in %s on line %d", + what, from, ZSTR_VAL(symbol), args, expected, + ZSTR_VAL(function->op_array.filename), function->op_array.line_start); + } else { + zend_throw_error(NULL, + "too many %s for %s of %s, %d given and a maximum of %d expected", + what, from, ZSTR_VAL(symbol), args, expected); + } +} + +void zend_partial_args_check(zend_execute_data *call) { + /* this is invoked by VM before the creation of zend_partial */ + zend_function *function = call->func; + + uint32_t num = ZEND_CALL_NUM_ARGS(call) + + ((ZEND_CALL_INFO(call) & ZEND_CALL_VARIADIC_PLACEHOLDER) ? -1 : 0); + + if (num < function->common.required_num_args) { + /* this check is delayed in the case of variadic application */ + if (ZEND_PARTIAL_CALL_FLAG(call, ZEND_CALL_VARIADIC_PLACEHOLDER)) { + return; + } + + zend_string *symbol = zend_partial_symbol_name(call, function); + zend_partial_args_underflow( + function, symbol, + num, function->common.required_num_args, false, true); + zend_string_release(symbol); + } else if (num > function->common.num_args && + !ZEND_PARTIAL_FUNC_FLAG(call->func, ZEND_ACC_VARIADIC)) { + zend_string *symbol = zend_partial_symbol_name(call, function); + zend_partial_args_overflow( + function, symbol, + num, function->common.num_args, false, true); + zend_string_release(symbol); + } +} + +static zend_always_inline uint32_t zend_partial_apply( + zval *pStart, zval *pEnd, + zval *cStart, zval *cEnd, + zval *fParam, bool call) { + + uint32_t pCount = 0; + + /* this optimizes the most general case, partial variadic application followed by + all arguments on call, and initial application */ + if ((pEnd - pStart) == 0 || + ((pEnd - pStart) == 1 && Z_IS_PLACEHOLDER_VARIADIC_P(pStart))) { + if ((pCount = (cEnd - cStart)) > 0) { + memcpy(fParam, cStart, sizeof(zval) * pCount); + } + + if (call) { + cStart = fParam; + cEnd = cStart + pCount; + while (cStart < cEnd) { + if (Z_IS_PLACEHOLDER_P(cStart)) { + ZVAL_UNDEF(cStart); + pCount--; + } + cStart++; + } + } + return pCount; + } + + /* this optimizes the second most general case: all arguments supplied upon first + application, followed by no arguments on call */ + if ((cEnd - cStart) == 0) { + if ((pCount = (pEnd - pStart)) > 0) { + memcpy(fParam, pStart, sizeof(zval) * pCount); + } + + if (call) { + cStart = fParam; + cEnd = cStart + pCount; + while (cStart < cEnd) { + if (Z_IS_PLACEHOLDER_P(cStart)) { + ZVAL_UNDEF(cStart); + pCount--; + } + cStart++; + } + } + return pCount; + } + + /* slow path is not able to handle all cases */ + while (pStart < pEnd) { + if (Z_IS_PLACEHOLDER_P(pStart)) { + if (cStart < cEnd) { + ZVAL_COPY_VALUE(fParam, cStart); + pCount++; + fParam++; + cStart++; + } + } else { + ZVAL_COPY_VALUE(fParam, pStart); + pCount++; + fParam++; + } + pStart++; + } + + while (cStart < cEnd) { + ZVAL_COPY_VALUE(fParam, cStart); + pCount++; + fParam++; + cStart++; + } + + return pCount; +} + +ZEND_NAMED_FUNCTION(zend_partial_call_magic) +{ + zend_partial *partial = (zend_partial*) Z_OBJ_P(ZEND_THIS); + zend_object *object = NULL; + zval *params; + uint32_t num_params, num_all_params; + HashTable *named_args; + zend_fcall_info fci = empty_fcall_info; + zend_fcall_info_cache fcc = empty_fcall_info_cache; + + ZEND_PARSE_PARAMETERS_START(0, -1) + Z_PARAM_VARIADIC_WITH_NAMED(params, num_params, named_args) + ZEND_PARSE_PARAMETERS_END(); + + num_all_params = num_params + (named_args ? named_args->nNumUsed : 0); + + if (num_all_params < partial->prototype.common.required_num_args) { + zend_string *symbol = zend_partial_symbol_name(execute_data, &partial->prototype); + zend_partial_prototype_underflow( + &partial->prototype, symbol, num_all_params, + partial->prototype.common.required_num_args, + ZEND_PARTIAL_CALL_FLAG(partial, ZEND_APPLY_VARIADIC)); + zend_string_release(symbol); + if (ZEND_PARTIAL_IS_CALL_TRAMPOLINE(&partial->prototype)) { + EG(trampoline).common.function_name = NULL; + } + RETURN_THROWS(); + } else if (num_all_params > partial->prototype.common.num_args && + !ZEND_PARTIAL_CALL_FLAG(partial, ZEND_APPLY_VARIADIC)) { + zend_string *symbol = zend_partial_symbol_name(execute_data, &partial->prototype); + zend_partial_prototype_overflow( + &partial->prototype, symbol, num_all_params, + partial->prototype.common.num_args); + zend_string_release(symbol); + if (ZEND_PARTIAL_IS_CALL_TRAMPOLINE(&partial->prototype)) { + EG(trampoline).common.function_name = NULL; + } + RETURN_THROWS(); + } + + if (Z_TYPE(partial->This) == IS_OBJECT) { + object = Z_OBJ(partial->This); + } else if (ZEND_PARTIAL_CALL_FLAG(partial, ZEND_APPLY_FACTORY)) { + zend_class_entry *type = Z_CE(partial->This); + zval instance; + + if (type->create_object) { + ZVAL_OBJ(&instance, type->create_object(type)); + } else { + ZVAL_OBJ(&instance, zend_objects_new(type)); + + object_properties_init(Z_OBJ(instance), type); + } + + object = Z_OBJ(instance); + + if (ZEND_PARTIAL_CALL_FLAG(partial, ZEND_APPLY_PASS)) { + /* nothing to pass any arguments too, so return immediately */ + RETURN_OBJ(object); + } + + GC_ADD_FLAGS(object, IS_OBJ_DESTRUCTOR_CALLED); + } + + fci.size = sizeof(zend_fcall_info); + fci.retval = return_value; + fcc.function_handler = &partial->func; + + if (object) { + fci.object = object; + fcc.object = object; + } + + if (partial->named) { + if (!named_args) { + named_args = partial->named; + GC_ADDREF(named_args); + } else { + HashTable *nested = zend_array_dup(partial->named); + zend_hash_merge(nested, named_args, zval_copy_ctor, true); + named_args = nested; + } + fci.named_params = named_args; + } else { + fci.named_params = named_args; + } + + fci.params = ecalloc(sizeof(zval), partial->argc + num_params); + fci.param_count = zend_partial_apply( + partial->argv, partial->argv + partial->argc, + params, params + num_params, fci.params, true); + + if (fci.param_count < partial->func.common.required_num_args) { + /* doesn't satisfy implementation */ + zend_string *symbol = zend_partial_symbol_name(execute_data, &partial->func); + zend_partial_args_underflow( + &partial->func, symbol, fci.param_count, + partial->func.common.required_num_args, true, false); + zend_string_release(symbol); + } else { + zend_call_function(&fci, &fcc); + } + + if (ZEND_PARTIAL_IS_CALL_TRAMPOLINE(&partial->prototype)) { + EG(trampoline).common.function_name = NULL; + } + + if (ZEND_PARTIAL_CALL_FLAG(partial, ZEND_APPLY_FACTORY)) { + if (!EG(exception)) { + GC_DEL_FLAGS(object, IS_OBJ_DESTRUCTOR_CALLED); + } + zval_ptr_dtor(return_value); + RETVAL_OBJ(object); + } + + if (partial->named) { + zend_array_release(named_args); + } + efree(fci.params); +} + +void zend_partial_create(zval *result, uint32_t info, zval *this_ptr, zend_function *function, uint32_t argc, zval *argv, zend_array *extra_named_params) { + zend_function *prototype = NULL; + + ZVAL_OBJ(result, zend_partial_new(zend_ce_closure, info)); + + zend_partial *applied, *partial = (zend_partial*) Z_OBJ_P(result); + + if ((applied = zend_partial_fetch(this_ptr))) { + ZEND_ADD_CALL_FLAG(partial, ZEND_CALL_INFO(applied) & ~ZEND_APPLY_VARIADIC); + + function = &applied->func; + prototype = &applied->prototype; + + if (ZEND_PARTIAL_CALL_FLAG(partial, ZEND_APPLY_FACTORY)) { + Z_CE(partial->This) = Z_CE(applied->This); + } + + partial->argv = ecalloc(applied->argc + argc, sizeof(zval)); + partial->argc = zend_partial_apply( + applied->argv, applied->argv + applied->argc, + argv, argv + argc, + partial->argv, false); + + if (extra_named_params) { + if (applied->named) { + partial->named = zend_array_dup(applied->named); + + zend_hash_merge(partial->named, extra_named_params, zval_copy_ctor, true); + } else { + partial->named = extra_named_params; + GC_ADDREF(extra_named_params); + } + } + } else { + partial->argv = ecalloc(argc, sizeof(zval)); + partial->argc = zend_partial_apply( + NULL, NULL, + argv, argv + argc, + partial->argv, false); + + if (extra_named_params) { + partial->named = extra_named_params; + GC_ADDREF(extra_named_params); + } + } + + memcpy(&partial->func, function, ZEND_PARTIAL_FUNC_SIZE(function)); + + ZEND_PARTIAL_FUNC_DEL(&partial->func, ZEND_ACC_CLOSURE); + ZEND_PARTIAL_FUNC_ADD(&partial->func, ZEND_ACC_IMMUTABLE); + + if (ZEND_PARTIAL_FUNC_FLAG(&partial->func, ZEND_ACC_CALL_VIA_TRAMPOLINE)) { + ZEND_PARTIAL_FUNC_ADD(&partial->func, ZEND_ACC_TRAMPOLINE_PERMANENT); + } + + if (ZEND_PARTIAL_CALL_FLAG(partial, ZEND_APPLY_FACTORY)) { + if (!Z_CE(partial->This)) { + Z_CE(partial->This) = Z_OBJCE_P(this_ptr); + } + + if (ZEND_PARTIAL_CALL_FLAG(partial, ZEND_APPLY_PASS)) { + /* setting scope for pass function so that errors make sense */ + partial->func.common.scope = Z_CE(partial->This); + } + } + + if (partial->func.type == ZEND_USER_FUNCTION) { + zend_string_addref(partial->func.common.function_name); + + partial->func.op_array.refcount = NULL; + } + + if (!prototype) { + prototype = &partial->func; + } + + partial->func.common.prototype = zend_partial_signature_create(partial, prototype); + + if (!ZEND_PARTIAL_CALL_FLAG(partial, ZEND_APPLY_FACTORY)) { + /* partial info may contain ZEND_APPLY_VARIADIC */ + uint32_t backup_info = ZEND_CALL_INFO(partial); + + if(Z_TYPE_P(this_ptr) == IS_UNDEF && Z_CE_P(this_ptr)) { + ZVAL_COPY_VALUE(&partial->This, this_ptr); + } else if (Z_TYPE_P(this_ptr) == IS_OBJECT) { + zval *This; + if (instanceof_function(Z_OBJCE_P(this_ptr), zend_ce_closure)) { + if (zend_string_equals_ci( + partial->func.common.function_name, + ZSTR_KNOWN(ZEND_STR_MAGIC_INVOKE))) { + This = this_ptr; + if (!ZEND_PARTIAL_FUNC_FLAG(function, ZEND_ACC_TRAMPOLINE_PERMANENT)) { + EG(trampoline).common.function_name = NULL; + efree(function); + } + } else { + This = zend_get_closure_this_ptr(this_ptr); + } + } else { + This = this_ptr; + } + ZVAL_COPY(&partial->This, This); + } + + ZEND_ADD_CALL_FLAG(partial, backup_info); + } + + zend_partial_trampoline_create(partial, &partial->trampoline); +} diff --git a/Zend/zend_partial.h b/Zend/zend_partial.h new file mode 100644 index 0000000000000..d434236457c7d --- /dev/null +++ b/Zend/zend_partial.h @@ -0,0 +1,38 @@ +/* + +----------------------------------------------------------------------+ + | Zend Engine | + +----------------------------------------------------------------------+ + | Copyright (c) Zend Technologies Ltd. (http://www.zend.com) | + +----------------------------------------------------------------------+ + | This source file is subject to version 2.00 of the Zend license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.zend.com/license/2_00.txt. | + | If you did not receive a copy of the Zend license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@zend.com so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: krakjoe | + +----------------------------------------------------------------------+ +*/ +#ifndef ZEND_PARTIAL_H +#define ZEND_PARTIAL_H + +BEGIN_EXTERN_C() + +void zend_partial_startup(void); + +#define ZEND_APPLY_NORMAL (1<<16) +#define ZEND_APPLY_FACTORY (1<<17) +#define ZEND_APPLY_PASS (1<<18) +#define ZEND_APPLY_VARIADIC (1<<19) + +void zend_partial_create(zval *result, uint32_t info, zval *this_ptr, zend_function *function, uint32_t argc, zval *argv, zend_array *extra_named_params); + +void zend_partial_args_check(zend_execute_data *call); + +ZEND_NAMED_FUNCTION(zend_partial_call_magic); + +END_EXTERN_C() + +#endif diff --git a/Zend/zend_types.h b/Zend/zend_types.h index 963362222d0eb..cb6f3437b7242 100644 --- a/Zend/zend_types.h +++ b/Zend/zend_types.h @@ -550,6 +550,10 @@ struct _zend_ast_ref { #define _IS_BOOL 18 #define _IS_NUMBER 19 +/* used for place holders */ +#define _IS_PLACEHOLDER_ARG 20 +#define _IS_PLACEHOLDER_VARIADIC 21 + static zend_always_inline zend_uchar zval_get_type(const zval* pz) { return pz->u1.v.type; } diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index e6a49d1c0d766..c0575d330a2ec 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -5702,7 +5702,7 @@ ZEND_VM_HANDLER(68, ZEND_NEW, UNUSED|CLASS_FETCH|CONST|VAR, UNUSED|CACHE_SLOT, N /* Perform a dummy function call */ call = zend_vm_stack_push_call_frame( ZEND_CALL_FUNCTION, (zend_function *) &zend_pass_function, - opline->extended_value, NULL); + opline->extended_value, Z_OBJ_P(result)); } else { if (EXPECTED(constructor->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&constructor->op_array))) { init_func_run_time_cache(&constructor->op_array); @@ -8770,6 +8770,89 @@ ZEND_VM_HANDLER(200, ZEND_FETCH_GLOBALS, UNUSED, UNUSED) ZEND_VM_NEXT_OPCODE(); } +ZEND_VM_HANDLER(202, ZEND_SEND_PLACEHOLDER, UNUSED, UNUSED) +{ + USE_OPLINE + zval *arg; + zend_execute_data *call = EX(call); + + arg = ZEND_CALL_ARG(call, opline->op2.num); + + Z_TYPE_INFO_P(arg) = opline->op1.num; + + if (Z_TYPE_INFO_P(arg) == _IS_PLACEHOLDER_VARIADIC) { + ZEND_ADD_CALL_FLAG(call, ZEND_CALL_VARIADIC_PLACEHOLDER); + } + + ZEND_VM_NEXT_OPCODE(); +} + +ZEND_VM_HANDLER(203, ZEND_DO_FCALL_PARTIAL, ANY, ANY) +{ + USE_OPLINE + zend_execute_data *call = EX(call); + zval *result = NULL; + uint32_t info = ZEND_APPLY_NORMAL; + + if (opline->op1_type != IS_UNUSED) { + result = EX_VAR(opline->op1.var); + + if (!(call->func->common.fn_flags & ZEND_ACC_CTOR)) { + ZEND_ADD_CALL_FLAG_EX(info, ZEND_APPLY_PASS); + } + + ZEND_ADD_CALL_FLAG_EX(info, ZEND_APPLY_FACTORY); + } else if (opline->result_type != IS_UNUSED) { + result = EX_VAR(opline->result.var); + } + + if (ZEND_CALL_INFO(call) & ZEND_CALL_VARIADIC_PLACEHOLDER) { + ZEND_ADD_CALL_FLAG_EX(info, ZEND_APPLY_VARIADIC); + } + + if (result) { + zend_partial_create(result, info, &call->This, call->func, + ZEND_CALL_NUM_ARGS(call), ZEND_CALL_ARG(call, 1), + ZEND_CALL_INFO(call) & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS ? + call->extra_named_params : NULL); + + if (info & ZEND_APPLY_FACTORY) { + GC_ADD_FLAGS(Z_OBJ(call->This), IS_OBJ_DESTRUCTOR_CALLED); + OBJ_RELEASE(Z_OBJ(call->This)); + } + } + + if (call->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) { + zend_free_trampoline(call->func); + } + + if (ZEND_CALL_INFO(call) & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS) { + zend_array_release(call->extra_named_params); + } + + if (ZEND_CALL_INFO(call) & ZEND_CALL_RELEASE_THIS) { + OBJ_RELEASE(Z_OBJ(call->This)); + } else if (ZEND_CALL_INFO(call) & ZEND_CALL_CLOSURE) { + OBJ_RELEASE(ZEND_CLOSURE_OBJECT(call->func)); + } + + EX(call) = call->prev_execute_data; + + zend_vm_stack_free_call_frame(call); + + ZEND_VM_NEXT_OPCODE(); +} + +ZEND_VM_HANDLER(204, ZEND_CHECK_PARTIAL_ARGS, UNUSED, UNUSED) +{ + USE_OPLINE + zend_execute_data *call = EX(call); + + SAVE_OPLINE(); + zend_partial_args_check(call); + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); +} + ZEND_VM_HANDLER(186, ZEND_ISSET_ISEMPTY_THIS, UNUSED, UNUSED) { USE_OPLINE diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 7fabd5d2673a5..bccccc105766b 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -3507,6 +3507,62 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CALL_TRAMPOLINE_SPEC_OBSERVER_ ZEND_VM_LEAVE(); } +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_PARTIAL_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_execute_data *call = EX(call); + zval *result = NULL; + uint32_t info = ZEND_APPLY_NORMAL; + + if (opline->op1_type != IS_UNUSED) { + result = EX_VAR(opline->op1.var); + + if (!(call->func->common.fn_flags & ZEND_ACC_CTOR)) { + ZEND_ADD_CALL_FLAG_EX(info, ZEND_APPLY_PASS); + } + + ZEND_ADD_CALL_FLAG_EX(info, ZEND_APPLY_FACTORY); + } else if (opline->result_type != IS_UNUSED) { + result = EX_VAR(opline->result.var); + } + + if (ZEND_CALL_INFO(call) & ZEND_CALL_VARIADIC_PLACEHOLDER) { + ZEND_ADD_CALL_FLAG_EX(info, ZEND_APPLY_VARIADIC); + } + + if (result) { + zend_partial_create(result, info, &call->This, call->func, + ZEND_CALL_NUM_ARGS(call), ZEND_CALL_ARG(call, 1), + ZEND_CALL_INFO(call) & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS ? + call->extra_named_params : NULL); + + if (info & ZEND_APPLY_FACTORY) { + GC_ADD_FLAGS(Z_OBJ(call->This), IS_OBJ_DESTRUCTOR_CALLED); + OBJ_RELEASE(Z_OBJ(call->This)); + } + } + + if (call->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) { + zend_free_trampoline(call->func); + } + + if (ZEND_CALL_INFO(call) & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS) { + zend_array_release(call->extra_named_params); + } + + if (ZEND_CALL_INFO(call) & ZEND_CALL_RELEASE_THIS) { + OBJ_RELEASE(Z_OBJ(call->This)); + } else if (ZEND_CALL_INFO(call) & ZEND_CALL_CLOSURE) { + OBJ_RELEASE(ZEND_CLOSURE_OBJECT(call->func)); + } + + EX(call) = call->prev_execute_data; + + zend_vm_stack_free_call_frame(call); + + ZEND_VM_NEXT_OPCODE(); +} + static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_JMP_FORWARD_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -10156,7 +10212,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_NEW_SPEC_CONST_UNUSED_HANDLER( /* Perform a dummy function call */ call = zend_vm_stack_push_call_frame( ZEND_CALL_FUNCTION, (zend_function *) &zend_pass_function, - opline->extended_value, NULL); + opline->extended_value, Z_OBJ_P(result)); } else { if (EXPECTED(constructor->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&constructor->op_array))) { init_func_run_time_cache(&constructor->op_array); @@ -28388,7 +28444,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_NEW_SPEC_VAR_UNUSED_HANDLER(ZE /* Perform a dummy function call */ call = zend_vm_stack_push_call_frame( ZEND_CALL_FUNCTION, (zend_function *) &zend_pass_function, - opline->extended_value, NULL); + opline->extended_value, Z_OBJ_P(result)); } else { if (EXPECTED(constructor->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&constructor->op_array))) { init_func_run_time_cache(&constructor->op_array); @@ -35196,7 +35252,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_NEW_SPEC_UNUSED_UNUSED_HANDLER /* Perform a dummy function call */ call = zend_vm_stack_push_call_frame( ZEND_CALL_FUNCTION, (zend_function *) &zend_pass_function, - opline->extended_value, NULL); + opline->extended_value, Z_OBJ_P(result)); } else { if (EXPECTED(constructor->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&constructor->op_array))) { init_func_run_time_cache(&constructor->op_array); @@ -35384,6 +35440,33 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_GLOBALS_SPEC_UNUSED_UNUS ZEND_VM_NEXT_OPCODE(); } +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_PLACEHOLDER_SPEC_UNUSED_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zval *arg; + zend_execute_data *call = EX(call); + + arg = ZEND_CALL_ARG(call, opline->op2.num); + + Z_TYPE_INFO_P(arg) = opline->op1.num; + + if (Z_TYPE_INFO_P(arg) == _IS_PLACEHOLDER_VARIADIC) { + ZEND_ADD_CALL_FLAG(call, ZEND_CALL_VARIADIC_PLACEHOLDER); + } + + ZEND_VM_NEXT_OPCODE(); +} + +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CHECK_PARTIAL_ARGS_SPEC_UNUSED_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_execute_data *call = EX(call); + + SAVE_OPLINE(); + zend_partial_args_check(call); + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); +} + static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ISSET_ISEMPTY_THIS_SPEC_UNUSED_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -53541,6 +53624,9 @@ ZEND_API void execute_ex(zend_execute_data *ex) (void*)&&ZEND_CHECK_UNDEF_ARGS_SPEC_UNUSED_UNUSED_LABEL, (void*)&&ZEND_FETCH_GLOBALS_SPEC_UNUSED_UNUSED_LABEL, (void*)&&ZEND_VERIFY_NEVER_TYPE_SPEC_UNUSED_UNUSED_LABEL, + (void*)&&ZEND_SEND_PLACEHOLDER_SPEC_UNUSED_UNUSED_LABEL, + (void*)&&ZEND_DO_FCALL_PARTIAL_SPEC_LABEL, + (void*)&&ZEND_CHECK_PARTIAL_ARGS_SPEC_UNUSED_UNUSED_LABEL, (void*)&&ZEND_RECV_NOTYPE_SPEC_LABEL, (void*)&&ZEND_JMP_FORWARD_SPEC_LABEL, (void*)&&ZEND_NULL_LABEL, @@ -54806,6 +54892,10 @@ ZEND_API void execute_ex(zend_execute_data *ex) VM_TRACE(ZEND_CALL_TRAMPOLINE_SPEC_OBSERVER) ZEND_CALL_TRAMPOLINE_SPEC_OBSERVER_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); HYBRID_BREAK(); + HYBRID_CASE(ZEND_DO_FCALL_PARTIAL_SPEC): + VM_TRACE(ZEND_DO_FCALL_PARTIAL_SPEC) + ZEND_DO_FCALL_PARTIAL_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + HYBRID_BREAK(); HYBRID_CASE(ZEND_JMP_FORWARD_SPEC): VM_TRACE(ZEND_JMP_FORWARD_SPEC) ZEND_JMP_FORWARD_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); @@ -57755,6 +57845,14 @@ ZEND_API void execute_ex(zend_execute_data *ex) VM_TRACE(ZEND_FETCH_GLOBALS_SPEC_UNUSED_UNUSED) ZEND_FETCH_GLOBALS_SPEC_UNUSED_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); HYBRID_BREAK(); + HYBRID_CASE(ZEND_SEND_PLACEHOLDER_SPEC_UNUSED_UNUSED): + VM_TRACE(ZEND_SEND_PLACEHOLDER_SPEC_UNUSED_UNUSED) + ZEND_SEND_PLACEHOLDER_SPEC_UNUSED_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + HYBRID_BREAK(); + HYBRID_CASE(ZEND_CHECK_PARTIAL_ARGS_SPEC_UNUSED_UNUSED): + VM_TRACE(ZEND_CHECK_PARTIAL_ARGS_SPEC_UNUSED_UNUSED) + ZEND_CHECK_PARTIAL_ARGS_SPEC_UNUSED_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + HYBRID_BREAK(); HYBRID_CASE(ZEND_ISSET_ISEMPTY_THIS_SPEC_UNUSED_UNUSED): VM_TRACE(ZEND_ISSET_ISEMPTY_THIS_SPEC_UNUSED_UNUSED) ZEND_ISSET_ISEMPTY_THIS_SPEC_UNUSED_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); @@ -61581,6 +61679,9 @@ void zend_vm_init(void) ZEND_CHECK_UNDEF_ARGS_SPEC_UNUSED_UNUSED_HANDLER, ZEND_FETCH_GLOBALS_SPEC_UNUSED_UNUSED_HANDLER, ZEND_VERIFY_NEVER_TYPE_SPEC_UNUSED_UNUSED_HANDLER, + ZEND_SEND_PLACEHOLDER_SPEC_UNUSED_UNUSED_HANDLER, + ZEND_DO_FCALL_PARTIAL_SPEC_HANDLER, + ZEND_CHECK_PARTIAL_ARGS_SPEC_UNUSED_UNUSED_HANDLER, ZEND_RECV_NOTYPE_SPEC_HANDLER, ZEND_JMP_FORWARD_SPEC_HANDLER, ZEND_NULL_HANDLER, @@ -62689,7 +62790,10 @@ void zend_vm_init(void) 2546, 2547, 2548, - 3452 + 2549, + 2550, + 2551, + 3455 }; #if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID) zend_opcode_handler_funcs = labels; @@ -62862,7 +62966,7 @@ ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 2551 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE; + spec = 2554 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE; if (op->op1_type < op->op2_type) { zend_swap_operands(op); } @@ -62870,7 +62974,7 @@ ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 2576 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE; + spec = 2579 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE; if (op->op1_type < op->op2_type) { zend_swap_operands(op); } @@ -62878,7 +62982,7 @@ ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 2601 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE; + spec = 2604 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE; if (op->op1_type < op->op2_type) { zend_swap_operands(op); } @@ -62889,17 +62993,17 @@ ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 2626 | SPEC_RULE_OP1 | SPEC_RULE_OP2; + spec = 2629 | SPEC_RULE_OP1 | SPEC_RULE_OP2; } else if (op1_info == MAY_BE_LONG && op2_info == MAY_BE_LONG) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 2651 | SPEC_RULE_OP1 | SPEC_RULE_OP2; + spec = 2654 | SPEC_RULE_OP1 | SPEC_RULE_OP2; } else if (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 2676 | SPEC_RULE_OP1 | SPEC_RULE_OP2; + spec = 2679 | SPEC_RULE_OP1 | SPEC_RULE_OP2; } break; case ZEND_MUL: @@ -62910,17 +63014,17 @@ ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 2701 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE; + spec = 2704 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE; } else if (op1_info == MAY_BE_LONG && op2_info == MAY_BE_LONG) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 2726 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE; + spec = 2729 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE; } else if (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 2751 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE; + spec = 2754 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE; } break; case ZEND_IS_IDENTICAL: @@ -62931,14 +63035,14 @@ ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 2776 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; + spec = 2779 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; } else if (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 2851 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; + spec = 2854 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; } else if (op->op1_type == IS_CV && (op->op2_type & (IS_CONST|IS_CV)) && !(op1_info & (MAY_BE_UNDEF|MAY_BE_REF)) && !(op2_info & (MAY_BE_UNDEF|MAY_BE_REF))) { - spec = 3076 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE; + spec = 3079 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE; } break; case ZEND_IS_NOT_IDENTICAL: @@ -62949,14 +63053,14 @@ ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 2926 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; + spec = 2929 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; } else if (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 3001 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; + spec = 3004 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; } else if (op->op1_type == IS_CV && (op->op2_type & (IS_CONST|IS_CV)) && !(op1_info & (MAY_BE_UNDEF|MAY_BE_REF)) && !(op2_info & (MAY_BE_UNDEF|MAY_BE_REF))) { - spec = 3081 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE; + spec = 3084 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE; } break; case ZEND_IS_EQUAL: @@ -62967,12 +63071,12 @@ ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 2776 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; + spec = 2779 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; } else if (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 2851 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; + spec = 2854 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; } break; case ZEND_IS_NOT_EQUAL: @@ -62983,12 +63087,12 @@ ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 2926 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; + spec = 2929 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; } else if (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 3001 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; + spec = 3004 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; } break; case ZEND_IS_SMALLER: @@ -62996,12 +63100,12 @@ ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 3086 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; + spec = 3089 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; } else if (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 3161 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; + spec = 3164 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; } break; case ZEND_IS_SMALLER_OR_EQUAL: @@ -63009,74 +63113,74 @@ ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 3236 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; + spec = 3239 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; } else if (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 3311 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; + spec = 3314 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; } break; case ZEND_QM_ASSIGN: if (op1_info == MAY_BE_LONG) { - spec = 3398 | SPEC_RULE_OP1; + spec = 3401 | SPEC_RULE_OP1; } else if (op1_info == MAY_BE_DOUBLE) { - spec = 3403 | SPEC_RULE_OP1; + spec = 3406 | SPEC_RULE_OP1; } else if ((op->op1_type == IS_CONST) ? !Z_REFCOUNTED_P(RT_CONSTANT(op, op->op1)) : (!(op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE))))) { - spec = 3408 | SPEC_RULE_OP1; + spec = 3411 | SPEC_RULE_OP1; } break; case ZEND_PRE_INC: if (res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG) { - spec = 3386 | SPEC_RULE_RETVAL; + spec = 3389 | SPEC_RULE_RETVAL; } else if (op1_info == MAY_BE_LONG) { - spec = 3388 | SPEC_RULE_RETVAL; + spec = 3391 | SPEC_RULE_RETVAL; } break; case ZEND_PRE_DEC: if (res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG) { - spec = 3390 | SPEC_RULE_RETVAL; + spec = 3393 | SPEC_RULE_RETVAL; } else if (op1_info == MAY_BE_LONG) { - spec = 3392 | SPEC_RULE_RETVAL; + spec = 3395 | SPEC_RULE_RETVAL; } break; case ZEND_POST_INC: if (res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG) { - spec = 3394; + spec = 3397; } else if (op1_info == MAY_BE_LONG) { - spec = 3395; + spec = 3398; } break; case ZEND_POST_DEC: if (res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG) { - spec = 3396; + spec = 3399; } else if (op1_info == MAY_BE_LONG) { - spec = 3397; + spec = 3400; } break; case ZEND_JMP: if (OP_JMP_ADDR(op, op->op1) > op) { - spec = 2550; + spec = 2553; } break; case ZEND_RECV: if (op->op2.num == MAY_BE_ANY) { - spec = 2549; + spec = 2552; } break; case ZEND_SEND_VAL: if (op->op1_type == IS_CONST && op->op2_type == IS_UNUSED && !Z_REFCOUNTED_P(RT_CONSTANT(op, op->op1))) { - spec = 3448; + spec = 3451; } break; case ZEND_SEND_VAR_EX: if (op->op2_type == IS_UNUSED && op->op2.num <= MAX_ARG_FLAG_NUM && (op1_info & (MAY_BE_UNDEF|MAY_BE_REF)) == 0) { - spec = 3443 | SPEC_RULE_OP1; + spec = 3446 | SPEC_RULE_OP1; } break; case ZEND_FE_FETCH_R: if (op->op2_type == IS_CV && (op1_info & (MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_ARRAY) { - spec = 3450 | SPEC_RULE_RETVAL; + spec = 3453 | SPEC_RULE_RETVAL; } break; case ZEND_FETCH_DIM_R: @@ -63084,17 +63188,17 @@ ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 3413 | SPEC_RULE_OP1 | SPEC_RULE_OP2; + spec = 3416 | SPEC_RULE_OP1 | SPEC_RULE_OP2; } break; case ZEND_SEND_VAL_EX: if (op->op2_type == IS_UNUSED && op->op2.num <= MAX_ARG_FLAG_NUM && op->op1_type == IS_CONST && !Z_REFCOUNTED_P(RT_CONSTANT(op, op->op1))) { - spec = 3449; + spec = 3452; } break; case ZEND_SEND_VAR: if (op->op2_type == IS_UNUSED && (op1_info & (MAY_BE_UNDEF|MAY_BE_REF)) == 0) { - spec = 3438 | SPEC_RULE_OP1; + spec = 3441 | SPEC_RULE_OP1; } break; case ZEND_BW_OR: diff --git a/Zend/zend_vm_handlers.h b/Zend/zend_vm_handlers.h index 8e500da57cbf3..e48479fbaf846 100644 --- a/Zend/zend_vm_handlers.h +++ b/Zend/zend_vm_handlers.h @@ -1354,498 +1354,501 @@ _(2546, ZEND_CHECK_UNDEF_ARGS_SPEC_UNUSED_UNUSED) \ _(2547, ZEND_FETCH_GLOBALS_SPEC_UNUSED_UNUSED) \ _(2548, ZEND_VERIFY_NEVER_TYPE_SPEC_UNUSED_UNUSED) \ - _(2549, ZEND_RECV_NOTYPE_SPEC) \ - _(2550, ZEND_JMP_FORWARD_SPEC) \ - _(2556, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_CONST) \ - _(2557, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ - _(2558, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2549, ZEND_SEND_PLACEHOLDER_SPEC_UNUSED_UNUSED) \ + _(2550, ZEND_DO_FCALL_PARTIAL_SPEC) \ + _(2551, ZEND_CHECK_PARTIAL_ARGS_SPEC_UNUSED_UNUSED) \ + _(2552, ZEND_RECV_NOTYPE_SPEC) \ + _(2553, ZEND_JMP_FORWARD_SPEC) \ + _(2559, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_CONST) \ _(2560, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ - _(2561, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_CONST) \ - _(2562, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2561, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ _(2563, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2564, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_CONST) \ _(2565, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ - _(2571, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_CONST) \ - _(2572, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ - _(2573, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2566, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2568, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2574, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_CONST) \ _(2575, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ - _(2581, ZEND_ADD_LONG_SPEC_TMPVARCV_CONST) \ - _(2582, ZEND_ADD_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2583, ZEND_ADD_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2576, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2578, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2584, ZEND_ADD_LONG_SPEC_TMPVARCV_CONST) \ _(2585, ZEND_ADD_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2586, ZEND_ADD_LONG_SPEC_TMPVARCV_CONST) \ - _(2587, ZEND_ADD_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2586, ZEND_ADD_LONG_SPEC_TMPVARCV_TMPVARCV) \ _(2588, ZEND_ADD_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2589, ZEND_ADD_LONG_SPEC_TMPVARCV_CONST) \ _(2590, ZEND_ADD_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2596, ZEND_ADD_LONG_SPEC_TMPVARCV_CONST) \ - _(2597, ZEND_ADD_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2598, ZEND_ADD_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2591, ZEND_ADD_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2593, ZEND_ADD_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2599, ZEND_ADD_LONG_SPEC_TMPVARCV_CONST) \ _(2600, ZEND_ADD_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2606, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_CONST) \ - _(2607, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2608, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2601, ZEND_ADD_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2603, ZEND_ADD_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2609, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_CONST) \ _(2610, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2611, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_CONST) \ - _(2612, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2611, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ _(2613, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2614, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_CONST) \ _(2615, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2621, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_CONST) \ - _(2622, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2623, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2616, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2618, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2624, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_CONST) \ _(2625, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2627, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_CONST_TMPVARCV) \ - _(2628, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_CONST_TMPVARCV) \ + _(2626, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2628, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ _(2630, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_CONST_TMPVARCV) \ - _(2631, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_CONST) \ - _(2632, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ - _(2633, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2631, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_CONST_TMPVARCV) \ + _(2633, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_CONST_TMPVARCV) \ + _(2634, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_CONST) \ _(2635, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ - _(2636, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_CONST) \ - _(2637, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2636, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ _(2638, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2639, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_CONST) \ _(2640, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ - _(2646, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_CONST) \ - _(2647, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ - _(2648, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2641, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2643, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2649, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_CONST) \ _(2650, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ - _(2652, ZEND_SUB_LONG_SPEC_CONST_TMPVARCV) \ - _(2653, ZEND_SUB_LONG_SPEC_CONST_TMPVARCV) \ + _(2651, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2653, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ _(2655, ZEND_SUB_LONG_SPEC_CONST_TMPVARCV) \ - _(2656, ZEND_SUB_LONG_SPEC_TMPVARCV_CONST) \ - _(2657, ZEND_SUB_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2658, ZEND_SUB_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2656, ZEND_SUB_LONG_SPEC_CONST_TMPVARCV) \ + _(2658, ZEND_SUB_LONG_SPEC_CONST_TMPVARCV) \ + _(2659, ZEND_SUB_LONG_SPEC_TMPVARCV_CONST) \ _(2660, ZEND_SUB_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2661, ZEND_SUB_LONG_SPEC_TMPVARCV_CONST) \ - _(2662, ZEND_SUB_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2661, ZEND_SUB_LONG_SPEC_TMPVARCV_TMPVARCV) \ _(2663, ZEND_SUB_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2664, ZEND_SUB_LONG_SPEC_TMPVARCV_CONST) \ _(2665, ZEND_SUB_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2671, ZEND_SUB_LONG_SPEC_TMPVARCV_CONST) \ - _(2672, ZEND_SUB_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2673, ZEND_SUB_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2666, ZEND_SUB_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2668, ZEND_SUB_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2674, ZEND_SUB_LONG_SPEC_TMPVARCV_CONST) \ _(2675, ZEND_SUB_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2677, ZEND_SUB_DOUBLE_SPEC_CONST_TMPVARCV) \ - _(2678, ZEND_SUB_DOUBLE_SPEC_CONST_TMPVARCV) \ + _(2676, ZEND_SUB_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2678, ZEND_SUB_LONG_SPEC_TMPVARCV_TMPVARCV) \ _(2680, ZEND_SUB_DOUBLE_SPEC_CONST_TMPVARCV) \ - _(2681, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_CONST) \ - _(2682, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2683, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2681, ZEND_SUB_DOUBLE_SPEC_CONST_TMPVARCV) \ + _(2683, ZEND_SUB_DOUBLE_SPEC_CONST_TMPVARCV) \ + _(2684, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_CONST) \ _(2685, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2686, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_CONST) \ - _(2687, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2686, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ _(2688, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2689, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_CONST) \ _(2690, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2696, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_CONST) \ - _(2697, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2698, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2691, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2693, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2699, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_CONST) \ _(2700, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2706, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_CONST) \ - _(2707, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ - _(2708, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2701, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2703, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2709, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_CONST) \ _(2710, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ - _(2711, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_CONST) \ - _(2712, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2711, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ _(2713, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2714, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_CONST) \ _(2715, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ - _(2721, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_CONST) \ - _(2722, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ - _(2723, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2716, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2718, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2724, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_CONST) \ _(2725, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ - _(2731, ZEND_MUL_LONG_SPEC_TMPVARCV_CONST) \ - _(2732, ZEND_MUL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2733, ZEND_MUL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2726, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2728, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2734, ZEND_MUL_LONG_SPEC_TMPVARCV_CONST) \ _(2735, ZEND_MUL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2736, ZEND_MUL_LONG_SPEC_TMPVARCV_CONST) \ - _(2737, ZEND_MUL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2736, ZEND_MUL_LONG_SPEC_TMPVARCV_TMPVARCV) \ _(2738, ZEND_MUL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2739, ZEND_MUL_LONG_SPEC_TMPVARCV_CONST) \ _(2740, ZEND_MUL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2746, ZEND_MUL_LONG_SPEC_TMPVARCV_CONST) \ - _(2747, ZEND_MUL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2748, ZEND_MUL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2741, ZEND_MUL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2743, ZEND_MUL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2749, ZEND_MUL_LONG_SPEC_TMPVARCV_CONST) \ _(2750, ZEND_MUL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2756, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_CONST) \ - _(2757, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2758, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2751, ZEND_MUL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2753, ZEND_MUL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2759, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_CONST) \ _(2760, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2761, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_CONST) \ - _(2762, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2761, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ _(2763, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2764, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_CONST) \ _(2765, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2771, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_CONST) \ - _(2772, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2773, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2766, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2768, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2774, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_CONST) \ _(2775, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2791, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_CONST) \ - _(2792, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ - _(2793, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(2794, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2795, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2796, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2776, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2778, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2794, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_CONST) \ + _(2795, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ + _(2796, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ _(2797, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ _(2798, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ _(2799, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(2803, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2804, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2805, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(2806, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_CONST) \ - _(2807, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ - _(2808, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(2809, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2810, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2811, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2800, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2801, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(2802, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2806, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2807, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(2808, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2809, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_CONST) \ + _(2810, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ + _(2811, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ _(2812, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ _(2813, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ _(2814, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(2818, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2819, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2820, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(2836, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_CONST) \ - _(2837, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ - _(2838, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(2839, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2840, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2841, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2815, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2816, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(2817, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2821, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2822, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(2823, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2839, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_CONST) \ + _(2840, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ + _(2841, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ _(2842, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ _(2843, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ _(2844, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(2848, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2849, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2850, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(2866, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST) \ - _(2867, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ - _(2868, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(2869, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2870, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2871, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2845, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2846, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(2847, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2851, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2852, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(2853, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2869, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST) \ + _(2870, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ + _(2871, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ _(2872, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ _(2873, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ _(2874, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(2878, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2879, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2880, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(2881, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST) \ - _(2882, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ - _(2883, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(2884, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2885, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2886, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2875, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2876, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(2877, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2881, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2882, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(2883, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2884, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST) \ + _(2885, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ + _(2886, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ _(2887, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ _(2888, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ _(2889, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(2893, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2894, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2895, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(2911, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST) \ - _(2912, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ - _(2913, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(2914, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2915, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2916, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2890, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2891, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(2892, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2896, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2897, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(2898, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2914, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST) \ + _(2915, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ + _(2916, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ _(2917, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ _(2918, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ _(2919, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(2923, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2924, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2925, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(2941, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_CONST) \ - _(2942, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ - _(2943, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(2944, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2945, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2946, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2920, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2921, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(2922, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2926, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2927, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(2928, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2944, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_CONST) \ + _(2945, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ + _(2946, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ _(2947, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ _(2948, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ _(2949, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(2953, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2954, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2955, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(2956, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_CONST) \ - _(2957, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ - _(2958, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(2959, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2960, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2961, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2950, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2951, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(2952, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2956, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2957, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(2958, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2959, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_CONST) \ + _(2960, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ + _(2961, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ _(2962, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ _(2963, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ _(2964, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(2968, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2969, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2970, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(2986, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_CONST) \ - _(2987, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ - _(2988, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(2989, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2990, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2991, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2965, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2966, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(2967, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2971, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2972, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(2973, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2989, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_CONST) \ + _(2990, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ + _(2991, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ _(2992, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ _(2993, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ _(2994, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(2998, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2999, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3000, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3016, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST) \ - _(3017, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ - _(3018, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(3019, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3020, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3021, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2995, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2996, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(2997, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3001, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(3002, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3003, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3019, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST) \ + _(3020, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ + _(3021, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ _(3022, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ _(3023, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ _(3024, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3028, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3029, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3030, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3031, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST) \ - _(3032, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ - _(3033, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(3034, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3035, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3036, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3025, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3026, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3027, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3031, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3032, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3033, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3034, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST) \ + _(3035, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ + _(3036, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ _(3037, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ _(3038, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ _(3039, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3043, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3044, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3045, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3061, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST) \ - _(3062, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ - _(3063, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(3064, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3065, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3066, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3040, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3041, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3042, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3046, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3047, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3048, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3064, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST) \ + _(3065, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ + _(3066, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ _(3067, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ _(3068, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ _(3069, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3073, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3074, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3075, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3076, ZEND_IS_IDENTICAL_NOTHROW_SPEC_CV_CONST) \ - _(3080, ZEND_IS_IDENTICAL_NOTHROW_SPEC_CV_CV) \ - _(3081, ZEND_IS_NOT_IDENTICAL_NOTHROW_SPEC_CV_CONST) \ - _(3085, ZEND_IS_NOT_IDENTICAL_NOTHROW_SPEC_CV_CV) \ - _(3089, ZEND_IS_SMALLER_LONG_SPEC_CONST_TMPVARCV) \ - _(3090, ZEND_IS_SMALLER_LONG_SPEC_CONST_TMPVARCV_JMPZ) \ - _(3091, ZEND_IS_SMALLER_LONG_SPEC_CONST_TMPVARCV_JMPNZ) \ + _(3070, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3071, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3072, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3076, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3077, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3078, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3079, ZEND_IS_IDENTICAL_NOTHROW_SPEC_CV_CONST) \ + _(3083, ZEND_IS_IDENTICAL_NOTHROW_SPEC_CV_CV) \ + _(3084, ZEND_IS_NOT_IDENTICAL_NOTHROW_SPEC_CV_CONST) \ + _(3088, ZEND_IS_NOT_IDENTICAL_NOTHROW_SPEC_CV_CV) \ _(3092, ZEND_IS_SMALLER_LONG_SPEC_CONST_TMPVARCV) \ _(3093, ZEND_IS_SMALLER_LONG_SPEC_CONST_TMPVARCV_JMPZ) \ _(3094, ZEND_IS_SMALLER_LONG_SPEC_CONST_TMPVARCV_JMPNZ) \ - _(3098, ZEND_IS_SMALLER_LONG_SPEC_CONST_TMPVARCV) \ - _(3099, ZEND_IS_SMALLER_LONG_SPEC_CONST_TMPVARCV_JMPZ) \ - _(3100, ZEND_IS_SMALLER_LONG_SPEC_CONST_TMPVARCV_JMPNZ) \ - _(3101, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_CONST) \ - _(3102, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ - _(3103, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(3104, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(3105, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3106, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3095, ZEND_IS_SMALLER_LONG_SPEC_CONST_TMPVARCV) \ + _(3096, ZEND_IS_SMALLER_LONG_SPEC_CONST_TMPVARCV_JMPZ) \ + _(3097, ZEND_IS_SMALLER_LONG_SPEC_CONST_TMPVARCV_JMPNZ) \ + _(3101, ZEND_IS_SMALLER_LONG_SPEC_CONST_TMPVARCV) \ + _(3102, ZEND_IS_SMALLER_LONG_SPEC_CONST_TMPVARCV_JMPZ) \ + _(3103, ZEND_IS_SMALLER_LONG_SPEC_CONST_TMPVARCV_JMPNZ) \ + _(3104, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_CONST) \ + _(3105, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ + _(3106, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ _(3107, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV) \ _(3108, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ _(3109, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3113, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(3114, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3115, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3116, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_CONST) \ - _(3117, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ - _(3118, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(3119, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(3120, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3121, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3110, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(3111, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3112, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3116, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(3117, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3118, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3119, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_CONST) \ + _(3120, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ + _(3121, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ _(3122, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV) \ _(3123, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ _(3124, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3128, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(3129, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3130, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3146, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_CONST) \ - _(3147, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ - _(3148, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(3149, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(3150, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3151, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3125, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(3126, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3127, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3131, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(3132, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3133, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3149, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_CONST) \ + _(3150, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ + _(3151, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ _(3152, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV) \ _(3153, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ _(3154, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3158, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(3159, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3160, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3164, ZEND_IS_SMALLER_DOUBLE_SPEC_CONST_TMPVARCV) \ - _(3165, ZEND_IS_SMALLER_DOUBLE_SPEC_CONST_TMPVARCV_JMPZ) \ - _(3166, ZEND_IS_SMALLER_DOUBLE_SPEC_CONST_TMPVARCV_JMPNZ) \ + _(3155, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(3156, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3157, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3161, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(3162, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3163, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ _(3167, ZEND_IS_SMALLER_DOUBLE_SPEC_CONST_TMPVARCV) \ _(3168, ZEND_IS_SMALLER_DOUBLE_SPEC_CONST_TMPVARCV_JMPZ) \ _(3169, ZEND_IS_SMALLER_DOUBLE_SPEC_CONST_TMPVARCV_JMPNZ) \ - _(3173, ZEND_IS_SMALLER_DOUBLE_SPEC_CONST_TMPVARCV) \ - _(3174, ZEND_IS_SMALLER_DOUBLE_SPEC_CONST_TMPVARCV_JMPZ) \ - _(3175, ZEND_IS_SMALLER_DOUBLE_SPEC_CONST_TMPVARCV_JMPNZ) \ - _(3176, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_CONST) \ - _(3177, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ - _(3178, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(3179, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3180, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3181, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3170, ZEND_IS_SMALLER_DOUBLE_SPEC_CONST_TMPVARCV) \ + _(3171, ZEND_IS_SMALLER_DOUBLE_SPEC_CONST_TMPVARCV_JMPZ) \ + _(3172, ZEND_IS_SMALLER_DOUBLE_SPEC_CONST_TMPVARCV_JMPNZ) \ + _(3176, ZEND_IS_SMALLER_DOUBLE_SPEC_CONST_TMPVARCV) \ + _(3177, ZEND_IS_SMALLER_DOUBLE_SPEC_CONST_TMPVARCV_JMPZ) \ + _(3178, ZEND_IS_SMALLER_DOUBLE_SPEC_CONST_TMPVARCV_JMPNZ) \ + _(3179, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_CONST) \ + _(3180, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ + _(3181, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ _(3182, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ _(3183, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ _(3184, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3188, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3189, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3190, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3191, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_CONST) \ - _(3192, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ - _(3193, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(3194, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3195, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3196, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3185, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3186, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3187, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3191, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3192, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3193, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3194, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_CONST) \ + _(3195, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ + _(3196, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ _(3197, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ _(3198, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ _(3199, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3203, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3204, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3205, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3221, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_CONST) \ - _(3222, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ - _(3223, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(3224, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3225, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3226, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3200, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3201, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3202, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3206, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3207, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3208, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3224, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_CONST) \ + _(3225, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ + _(3226, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ _(3227, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ _(3228, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ _(3229, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3233, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3234, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3235, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3239, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_CONST_TMPVARCV) \ - _(3240, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_CONST_TMPVARCV_JMPZ) \ - _(3241, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_CONST_TMPVARCV_JMPNZ) \ + _(3230, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3231, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3232, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3236, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3237, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3238, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ _(3242, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_CONST_TMPVARCV) \ _(3243, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_CONST_TMPVARCV_JMPZ) \ _(3244, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_CONST_TMPVARCV_JMPNZ) \ - _(3248, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_CONST_TMPVARCV) \ - _(3249, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_CONST_TMPVARCV_JMPZ) \ - _(3250, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_CONST_TMPVARCV_JMPNZ) \ - _(3251, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_CONST) \ - _(3252, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ - _(3253, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(3254, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(3255, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3256, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3245, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_CONST_TMPVARCV) \ + _(3246, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_CONST_TMPVARCV_JMPZ) \ + _(3247, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_CONST_TMPVARCV_JMPNZ) \ + _(3251, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_CONST_TMPVARCV) \ + _(3252, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_CONST_TMPVARCV_JMPZ) \ + _(3253, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_CONST_TMPVARCV_JMPNZ) \ + _(3254, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_CONST) \ + _(3255, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ + _(3256, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ _(3257, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ _(3258, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ _(3259, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3263, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(3264, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3265, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3266, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_CONST) \ - _(3267, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ - _(3268, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(3269, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(3270, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3271, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3260, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(3261, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3262, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3266, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(3267, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3268, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3269, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_CONST) \ + _(3270, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ + _(3271, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ _(3272, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ _(3273, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ _(3274, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3278, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(3279, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3280, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3296, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_CONST) \ - _(3297, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ - _(3298, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(3299, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(3300, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3301, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3275, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(3276, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3277, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3281, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(3282, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3283, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3299, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_CONST) \ + _(3300, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ + _(3301, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ _(3302, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ _(3303, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ _(3304, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3308, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(3309, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3310, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3314, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_CONST_TMPVARCV) \ - _(3315, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_CONST_TMPVARCV_JMPZ) \ - _(3316, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_CONST_TMPVARCV_JMPNZ) \ + _(3305, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(3306, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3307, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3311, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(3312, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3313, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ _(3317, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_CONST_TMPVARCV) \ _(3318, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_CONST_TMPVARCV_JMPZ) \ _(3319, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_CONST_TMPVARCV_JMPNZ) \ - _(3323, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_CONST_TMPVARCV) \ - _(3324, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_CONST_TMPVARCV_JMPZ) \ - _(3325, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_CONST_TMPVARCV_JMPNZ) \ - _(3326, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST) \ - _(3327, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ - _(3328, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(3329, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3330, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3331, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3320, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_CONST_TMPVARCV) \ + _(3321, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_CONST_TMPVARCV_JMPZ) \ + _(3322, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_CONST_TMPVARCV_JMPNZ) \ + _(3326, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_CONST_TMPVARCV) \ + _(3327, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_CONST_TMPVARCV_JMPZ) \ + _(3328, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_CONST_TMPVARCV_JMPNZ) \ + _(3329, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST) \ + _(3330, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ + _(3331, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ _(3332, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ _(3333, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ _(3334, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3338, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3339, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3340, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3341, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST) \ - _(3342, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ - _(3343, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(3344, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3345, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3346, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3335, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3336, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3337, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3341, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3342, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3343, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3344, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST) \ + _(3345, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ + _(3346, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ _(3347, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ _(3348, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ _(3349, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3353, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3354, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3355, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3371, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST) \ - _(3372, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ - _(3373, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(3374, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3375, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3376, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3350, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3351, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3352, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3356, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3357, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3358, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3374, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST) \ + _(3375, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ + _(3376, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ _(3377, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ _(3378, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ _(3379, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3383, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3384, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3385, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3386, ZEND_PRE_INC_LONG_NO_OVERFLOW_SPEC_CV_RETVAL_UNUSED) \ - _(3387, ZEND_PRE_INC_LONG_NO_OVERFLOW_SPEC_CV_RETVAL_USED) \ - _(3388, ZEND_PRE_INC_LONG_SPEC_CV_RETVAL_UNUSED) \ - _(3389, ZEND_PRE_INC_LONG_SPEC_CV_RETVAL_USED) \ - _(3390, ZEND_PRE_DEC_LONG_NO_OVERFLOW_SPEC_CV_RETVAL_UNUSED) \ - _(3391, ZEND_PRE_DEC_LONG_NO_OVERFLOW_SPEC_CV_RETVAL_USED) \ - _(3392, ZEND_PRE_DEC_LONG_SPEC_CV_RETVAL_UNUSED) \ - _(3393, ZEND_PRE_DEC_LONG_SPEC_CV_RETVAL_USED) \ - _(3394, ZEND_POST_INC_LONG_NO_OVERFLOW_SPEC_CV) \ - _(3395, ZEND_POST_INC_LONG_SPEC_CV) \ - _(3396, ZEND_POST_DEC_LONG_NO_OVERFLOW_SPEC_CV) \ - _(3397, ZEND_POST_DEC_LONG_SPEC_CV) \ - _(3398, ZEND_QM_ASSIGN_LONG_SPEC_CONST) \ - _(3399, ZEND_QM_ASSIGN_LONG_SPEC_TMPVARCV) \ - _(3400, ZEND_QM_ASSIGN_LONG_SPEC_TMPVARCV) \ + _(3380, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3381, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3382, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3386, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3387, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3388, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3389, ZEND_PRE_INC_LONG_NO_OVERFLOW_SPEC_CV_RETVAL_UNUSED) \ + _(3390, ZEND_PRE_INC_LONG_NO_OVERFLOW_SPEC_CV_RETVAL_USED) \ + _(3391, ZEND_PRE_INC_LONG_SPEC_CV_RETVAL_UNUSED) \ + _(3392, ZEND_PRE_INC_LONG_SPEC_CV_RETVAL_USED) \ + _(3393, ZEND_PRE_DEC_LONG_NO_OVERFLOW_SPEC_CV_RETVAL_UNUSED) \ + _(3394, ZEND_PRE_DEC_LONG_NO_OVERFLOW_SPEC_CV_RETVAL_USED) \ + _(3395, ZEND_PRE_DEC_LONG_SPEC_CV_RETVAL_UNUSED) \ + _(3396, ZEND_PRE_DEC_LONG_SPEC_CV_RETVAL_USED) \ + _(3397, ZEND_POST_INC_LONG_NO_OVERFLOW_SPEC_CV) \ + _(3398, ZEND_POST_INC_LONG_SPEC_CV) \ + _(3399, ZEND_POST_DEC_LONG_NO_OVERFLOW_SPEC_CV) \ + _(3400, ZEND_POST_DEC_LONG_SPEC_CV) \ + _(3401, ZEND_QM_ASSIGN_LONG_SPEC_CONST) \ _(3402, ZEND_QM_ASSIGN_LONG_SPEC_TMPVARCV) \ - _(3403, ZEND_QM_ASSIGN_DOUBLE_SPEC_CONST) \ - _(3404, ZEND_QM_ASSIGN_DOUBLE_SPEC_TMPVARCV) \ - _(3405, ZEND_QM_ASSIGN_DOUBLE_SPEC_TMPVARCV) \ + _(3403, ZEND_QM_ASSIGN_LONG_SPEC_TMPVARCV) \ + _(3405, ZEND_QM_ASSIGN_LONG_SPEC_TMPVARCV) \ + _(3406, ZEND_QM_ASSIGN_DOUBLE_SPEC_CONST) \ _(3407, ZEND_QM_ASSIGN_DOUBLE_SPEC_TMPVARCV) \ - _(3408, ZEND_QM_ASSIGN_NOREF_SPEC_CONST) \ - _(3409, ZEND_QM_ASSIGN_NOREF_SPEC_TMPVARCV) \ - _(3410, ZEND_QM_ASSIGN_NOREF_SPEC_TMPVARCV) \ + _(3408, ZEND_QM_ASSIGN_DOUBLE_SPEC_TMPVARCV) \ + _(3410, ZEND_QM_ASSIGN_DOUBLE_SPEC_TMPVARCV) \ + _(3411, ZEND_QM_ASSIGN_NOREF_SPEC_CONST) \ _(3412, ZEND_QM_ASSIGN_NOREF_SPEC_TMPVARCV) \ - _(3414, ZEND_FETCH_DIM_R_INDEX_SPEC_CONST_TMPVARCV) \ - _(3415, ZEND_FETCH_DIM_R_INDEX_SPEC_CONST_TMPVARCV) \ + _(3413, ZEND_QM_ASSIGN_NOREF_SPEC_TMPVARCV) \ + _(3415, ZEND_QM_ASSIGN_NOREF_SPEC_TMPVARCV) \ _(3417, ZEND_FETCH_DIM_R_INDEX_SPEC_CONST_TMPVARCV) \ - _(3418, ZEND_FETCH_DIM_R_INDEX_SPEC_TMPVAR_CONST) \ - _(3419, ZEND_FETCH_DIM_R_INDEX_SPEC_TMPVAR_TMPVARCV) \ - _(3420, ZEND_FETCH_DIM_R_INDEX_SPEC_TMPVAR_TMPVARCV) \ + _(3418, ZEND_FETCH_DIM_R_INDEX_SPEC_CONST_TMPVARCV) \ + _(3420, ZEND_FETCH_DIM_R_INDEX_SPEC_CONST_TMPVARCV) \ + _(3421, ZEND_FETCH_DIM_R_INDEX_SPEC_TMPVAR_CONST) \ _(3422, ZEND_FETCH_DIM_R_INDEX_SPEC_TMPVAR_TMPVARCV) \ - _(3423, ZEND_FETCH_DIM_R_INDEX_SPEC_TMPVAR_CONST) \ - _(3424, ZEND_FETCH_DIM_R_INDEX_SPEC_TMPVAR_TMPVARCV) \ + _(3423, ZEND_FETCH_DIM_R_INDEX_SPEC_TMPVAR_TMPVARCV) \ _(3425, ZEND_FETCH_DIM_R_INDEX_SPEC_TMPVAR_TMPVARCV) \ + _(3426, ZEND_FETCH_DIM_R_INDEX_SPEC_TMPVAR_CONST) \ _(3427, ZEND_FETCH_DIM_R_INDEX_SPEC_TMPVAR_TMPVARCV) \ - _(3433, ZEND_FETCH_DIM_R_INDEX_SPEC_CV_CONST) \ - _(3434, ZEND_FETCH_DIM_R_INDEX_SPEC_CV_TMPVARCV) \ - _(3435, ZEND_FETCH_DIM_R_INDEX_SPEC_CV_TMPVARCV) \ + _(3428, ZEND_FETCH_DIM_R_INDEX_SPEC_TMPVAR_TMPVARCV) \ + _(3430, ZEND_FETCH_DIM_R_INDEX_SPEC_TMPVAR_TMPVARCV) \ + _(3436, ZEND_FETCH_DIM_R_INDEX_SPEC_CV_CONST) \ _(3437, ZEND_FETCH_DIM_R_INDEX_SPEC_CV_TMPVARCV) \ - _(3440, ZEND_SEND_VAR_SIMPLE_SPEC_VAR) \ - _(3442, ZEND_SEND_VAR_SIMPLE_SPEC_CV) \ - _(3445, ZEND_SEND_VAR_EX_SIMPLE_SPEC_VAR_UNUSED) \ - _(3447, ZEND_SEND_VAR_EX_SIMPLE_SPEC_CV_UNUSED) \ - _(3448, ZEND_SEND_VAL_SIMPLE_SPEC_CONST) \ - _(3449, ZEND_SEND_VAL_EX_SIMPLE_SPEC_CONST) \ - _(3450, ZEND_FE_FETCH_R_SIMPLE_SPEC_VAR_CV_RETVAL_UNUSED) \ - _(3451, ZEND_FE_FETCH_R_SIMPLE_SPEC_VAR_CV_RETVAL_USED) \ - _(3451+1, ZEND_NULL) + _(3438, ZEND_FETCH_DIM_R_INDEX_SPEC_CV_TMPVARCV) \ + _(3440, ZEND_FETCH_DIM_R_INDEX_SPEC_CV_TMPVARCV) \ + _(3443, ZEND_SEND_VAR_SIMPLE_SPEC_VAR) \ + _(3445, ZEND_SEND_VAR_SIMPLE_SPEC_CV) \ + _(3448, ZEND_SEND_VAR_EX_SIMPLE_SPEC_VAR_UNUSED) \ + _(3450, ZEND_SEND_VAR_EX_SIMPLE_SPEC_CV_UNUSED) \ + _(3451, ZEND_SEND_VAL_SIMPLE_SPEC_CONST) \ + _(3452, ZEND_SEND_VAL_EX_SIMPLE_SPEC_CONST) \ + _(3453, ZEND_FE_FETCH_R_SIMPLE_SPEC_VAR_CV_RETVAL_UNUSED) \ + _(3454, ZEND_FE_FETCH_R_SIMPLE_SPEC_VAR_CV_RETVAL_USED) \ + _(3454+1, ZEND_NULL) diff --git a/Zend/zend_vm_opcodes.c b/Zend/zend_vm_opcodes.c index 83c3517807755..5a9cfcaf718a9 100644 --- a/Zend/zend_vm_opcodes.c +++ b/Zend/zend_vm_opcodes.c @@ -22,7 +22,7 @@ #include #include -static const char *zend_vm_opcodes_names[202] = { +static const char *zend_vm_opcodes_names[205] = { "ZEND_NOP", "ZEND_ADD", "ZEND_SUB", @@ -225,9 +225,12 @@ static const char *zend_vm_opcodes_names[202] = { "ZEND_CHECK_UNDEF_ARGS", "ZEND_FETCH_GLOBALS", "ZEND_VERIFY_NEVER_TYPE", + "ZEND_SEND_PLACEHOLDER", + "ZEND_DO_FCALL_PARTIAL", + "ZEND_CHECK_PARTIAL_ARGS", }; -static uint32_t zend_vm_opcodes_flags[202] = { +static uint32_t zend_vm_opcodes_flags[205] = { 0x00000000, 0x00000b0b, 0x00000b0b, @@ -430,6 +433,9 @@ static uint32_t zend_vm_opcodes_flags[202] = { 0x00000101, 0x00000101, 0x00000101, + 0x00000101, + 0x00000000, + 0x00000101, }; ZEND_API const char* ZEND_FASTCALL zend_get_opcode_name(zend_uchar opcode) { diff --git a/Zend/zend_vm_opcodes.h b/Zend/zend_vm_opcodes.h index 94e74c0a57f12..e5d5effbebbbe 100644 --- a/Zend/zend_vm_opcodes.h +++ b/Zend/zend_vm_opcodes.h @@ -285,7 +285,10 @@ END_EXTERN_C() #define ZEND_CHECK_UNDEF_ARGS 199 #define ZEND_FETCH_GLOBALS 200 #define ZEND_VERIFY_NEVER_TYPE 201 +#define ZEND_SEND_PLACEHOLDER 202 +#define ZEND_DO_FCALL_PARTIAL 203 +#define ZEND_CHECK_PARTIAL_ARGS 204 -#define ZEND_VM_LAST_OPCODE 201 +#define ZEND_VM_LAST_OPCODE 204 #endif diff --git a/configure.ac b/configure.ac index e63c0b969fd34..0424fe1a659e4 100644 --- a/configure.ac +++ b/configure.ac @@ -1608,7 +1608,7 @@ PHP_ADD_SOURCES(Zend, \ zend_closures.c zend_weakrefs.c zend_float.c zend_string.c zend_signal.c zend_generators.c \ zend_virtual_cwd.c zend_ast.c zend_objects.c zend_object_handlers.c zend_objects_API.c \ zend_default_classes.c zend_inheritance.c zend_smart_str.c zend_cpuinfo.c zend_gdb.c \ - zend_observer.c zend_system_id.c zend_enum.c zend_fibers.c \ + zend_observer.c zend_system_id.c zend_enum.c zend_fibers.c zend_partial.c \ Optimizer/zend_optimizer.c \ Optimizer/pass1.c \ Optimizer/pass3.c \ diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 5ff8dc6f515ab..ed2423cd6a479 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -200,6 +200,7 @@ static zend_function *_copy_function(zend_function *fptr) /* {{{ */ zend_function *copy_fptr; copy_fptr = emalloc(sizeof(zend_function)); memcpy(copy_fptr, fptr, sizeof(zend_function)); + copy_fptr->internal_function.fn_flags &= ~ZEND_ACC_TRAMPOLINE_PERMANENT; copy_fptr->internal_function.function_name = zend_string_copy(fptr->internal_function.function_name); return copy_fptr; } else { @@ -588,6 +589,10 @@ static void _class_const_string(smart_str *str, char *name, zend_class_constant static zend_op *get_recv_op(zend_op_array *op_array, uint32_t offset) { + if (op_array->fn_flags & ZEND_ACC_PARTIAL) { + op_array = (zend_op_array*) op_array->prototype; + } + zend_op *op = op_array->opcodes; zend_op *end = op + op_array->last; @@ -600,15 +605,21 @@ static zend_op *get_recv_op(zend_op_array *op_array, uint32_t offset) } ++op; } - ZEND_ASSERT(0 && "Failed to find op"); + return NULL; } static zval *get_default_from_recv(zend_op_array *op_array, uint32_t offset) { + zend_op *recv = get_recv_op(op_array, offset); - if (!recv || recv->opcode != ZEND_RECV_INIT) { + + if (!recv) { return NULL; } + + if (recv->opcode != ZEND_RECV_INIT) { + return NULL; + } return RT_CONSTANT(recv, recv->op2); } @@ -803,6 +814,9 @@ static void _function_string(smart_str *str, zend_function *fptr, zend_class_ent if (fptr->common.fn_flags & ZEND_ACC_ABSTRACT) { smart_str_appends(str, "abstract "); } + if (fptr->common.fn_flags & ZEND_ACC_PARTIAL) { + smart_str_appends(str, "partial "); + } if (fptr->common.fn_flags & ZEND_ACC_FINAL) { smart_str_appends(str, "final "); } @@ -1289,6 +1303,31 @@ static void reflection_extension_factory(zval *object, const char *name_str) } /* }}} */ +static zend_always_inline uint32_t reflection_parameter_partial_offset(zend_function *fptr, zend_arg_info *info) { + zend_arg_info *arg = fptr->common.prototype->common.arg_info, + *end = arg + fptr->common.prototype->common.num_args; + uint32_t offset = 0; + + if (fptr->type == ZEND_USER_FUNCTION && + fptr->op_array.opcodes == &EG(call_trampoline_op)) { + return 0; + } + + if (fptr->common.fn_flags & ZEND_ACC_VARIADIC) { + end++; + } + + while (arg < end) { + if (zend_string_equals_ci(info->name, arg->name)) { + return offset; + } + offset++; + arg++; + } + ZEND_ASSERT(0); + return -1; +} + /* {{{ reflection_parameter_factory */ static void reflection_parameter_factory(zend_function *fptr, zval *closure_object, struct _zend_arg_info *arg_info, uint32_t offset, bool required, zval *object) { @@ -1300,7 +1339,11 @@ static void reflection_parameter_factory(zend_function *fptr, zval *closure_obje intern = Z_REFLECTION_P(object); reference = (parameter_reference*) emalloc(sizeof(parameter_reference)); reference->arg_info = arg_info; - reference->offset = offset; + if (fptr->common.fn_flags & ZEND_ACC_PARTIAL) { + reference->offset = reflection_parameter_partial_offset(fptr, arg_info); + } else { + reference->offset = offset; + } reference->required = required; reference->fptr = fptr; intern->ptr = reference; @@ -1569,7 +1612,9 @@ ZEND_METHOD(ReflectionFunction, __construct) zval_ptr_dtor(reflection_prop_name(object)); } - ZVAL_STR_COPY(reflection_prop_name(object), fptr->common.function_name); + if (fptr->common.function_name) { + ZVAL_STR_COPY(reflection_prop_name(object), fptr->common.function_name); + } intern->ptr = fptr; intern->ref_type = REF_TYPE_FUNCTION; if (closure_obj) { @@ -1622,7 +1667,21 @@ ZEND_METHOD(ReflectionFunctionAbstract, isClosure) RETURN_THROWS(); } GET_REFLECTION_OBJECT_PTR(fptr); - RETURN_BOOL(fptr->common.fn_flags & ZEND_ACC_CLOSURE); + RETURN_BOOL(fptr->common.fn_flags & (ZEND_ACC_CLOSURE|ZEND_ACC_PARTIAL)); +} +/* }}} */ + +/* {{{ Returns whether this is a partial closure */ +ZEND_METHOD(ReflectionFunctionAbstract, isPartial) +{ + reflection_object *intern; + zend_function *fptr; + + if (zend_parse_parameters_none() == FAILURE) { + RETURN_THROWS(); + } + GET_REFLECTION_OBJECT_PTR(fptr); + RETURN_BOOL(fptr->common.fn_flags & ZEND_ACC_PARTIAL); } /* }}} */ @@ -1638,7 +1697,7 @@ ZEND_METHOD(ReflectionFunctionAbstract, getClosureThis) GET_REFLECTION_OBJECT(); if (!Z_ISUNDEF(intern->obj)) { closure_this = zend_get_closure_this_ptr(&intern->obj); - if (!Z_ISUNDEF_P(closure_this)) { + if (closure_this && Z_TYPE_P(closure_this) == IS_OBJECT) { RETURN_OBJ_COPY(Z_OBJ_P(closure_this)); } } @@ -1657,6 +1716,7 @@ ZEND_METHOD(ReflectionFunctionAbstract, getClosureScopeClass) GET_REFLECTION_OBJECT(); if (!Z_ISUNDEF(intern->obj)) { closure_func = zend_get_closure_method_def(Z_OBJ(intern->obj)); + if (closure_func && closure_func->common.scope) { zend_reflection_class_factory(closure_func->common.scope, return_value); } diff --git a/win32/build/config.w32 b/win32/build/config.w32 index 28f9a1f320793..ae1dd3823f09f 100644 --- a/win32/build/config.w32 +++ b/win32/build/config.w32 @@ -238,7 +238,7 @@ ADD_SOURCES("Zend", "zend_language_parser.c zend_language_scanner.c \ zend_default_classes.c zend_execute.c zend_strtod.c zend_gc.c zend_closures.c zend_weakrefs.c \ zend_float.c zend_string.c zend_generators.c zend_virtual_cwd.c zend_ast.c \ zend_inheritance.c zend_smart_str.c zend_cpuinfo.c zend_observer.c zend_system_id.c \ - zend_enum.c zend_fibers.c"); + zend_enum.c zend_fibers.c zend_partial.c"); ADD_SOURCES("Zend\\Optimizer", "zend_optimizer.c pass1.c pass3.c optimize_func_calls.c block_pass.c optimize_temp_vars_5.c nop_removal.c compact_literals.c zend_cfg.c zend_dfg.c dfa_pass.c zend_ssa.c zend_inference.c zend_func_info.c zend_call_graph.c zend_dump.c escape_analysis.c compact_vars.c dce.c sccp.c scdf.c"); var FIBER_ASSEMBLER = X64 ? PATH_PROG('ML64') : PATH_PROG('ML'); From f522e46762d87acf5967355551c097ec77ebfd1a Mon Sep 17 00:00:00 2001 From: Joe Watkins Date: Fri, 4 Jun 2021 11:31:12 +0200 Subject: [PATCH 02/35] test coverage --- .../tests/partial_application/errors_003.phpt | 35 +++++++++---- Zend/tests/partial_application/magic_001.phpt | 51 ++++++++++++++++++- Zend/tests/partial_application/magic_002.phpt | 37 +++++++++++++- Zend/zend_partial.c | 9 ++-- 4 files changed, 113 insertions(+), 19 deletions(-) diff --git a/Zend/tests/partial_application/errors_003.phpt b/Zend/tests/partial_application/errors_003.phpt index 15b32592208bc..0ce69bc9ad65b 100644 --- a/Zend/tests/partial_application/errors_003.phpt +++ b/Zend/tests/partial_application/errors_003.phpt @@ -32,14 +32,6 @@ try { printf("%s\n", $ex->getMessage()); } -$usleep = usleep(...); - -try { - $usleep(); -} catch (Error $ex) { - printf("%s\n", $ex->getMessage()); -} - class Foo { public function bar($a, ...$b) {} } @@ -54,12 +46,33 @@ try { printf("%s\n", $ex->getMessage()); } +$usleep = usleep(...); + +try { + $usleep(); +} catch (Error $ex) { + printf("%s\n", $ex->getMessage()); +} + +$usleep = usleep(?); + +try { + $usleep(); +} catch (Error $ex) { + printf("%s\n", $ex->getMessage()); +} + +try { + $usleep(1, 2); +} catch (Error $ex) { + printf("%s\n", $ex->getMessage()); +} ?> --EXPECTF-- not enough arguments for application of foo, 0 given and exactly 1 expected, declared in %s on line 8 not enough arguments for application of foo, 1 given and exactly 2 expected, declared in %s on line 16 not enough arguments for application of bar, 1 given and at least 2 expected, declared in %s on line 24 +not enough arguments for application of Foo::bar, 0 given and exactly 1 expected, declared in %s on line 38 not enough arguments for implementation of usleep, 0 given and exactly 1 expected -not enough arguments for application of Foo::bar, 0 given and exactly 1 expected, declared in %s on line 46 - - +not enough arguments for application of usleep, 0 given and exactly 1 expected +too many arguments for application of usleep, 2 given and a maximum of 1 expected diff --git a/Zend/tests/partial_application/magic_001.phpt b/Zend/tests/partial_application/magic_001.phpt index 56488a526cbfc..db8770fbdc41e 100644 --- a/Zend/tests/partial_application/magic_001.phpt +++ b/Zend/tests/partial_application/magic_001.phpt @@ -5,6 +5,8 @@ Partial application magic: __call class Foo { public function __call($method, $args) { printf("%s::%s\n", __CLASS__, $method); + + var_dump(...$args); } } @@ -14,14 +16,61 @@ $bar = $foo->method(?); echo (string) new ReflectionFunction($bar); +try { + $bar(); +} catch (Error $ex) { + printf("%s\n", $ex->getMessage()); +} + +try { + $bar(1, 2); +} catch (Error $ex) { + printf("%s\n", $ex->getMessage()); +} + $bar(1); + +$bar = $foo->method(?, ...); + +echo (string) new ReflectionFunction($bar); + +$bar(10); + +$bar = $foo->method(...); + +echo (string) new ReflectionFunction($bar); + +$bar(100); ?> --EXPECTF-- Method [ partial public method method ] { - @@ %s 10 - 10 + @@ %s 12 - 12 - Parameters [1] { Parameter #0 [ $args ] } } +not enough arguments for application of Foo::method, 0 given and exactly 1 expected, declared in %s on line 12 +too many arguments for application of Foo::method, 2 given and a maximum of 1 expected, declared in %s on line 12 Foo::method +int(1) +Method [ partial public method method ] { + @@ %s 30 - 30 + + - Parameters [2] { + Parameter #0 [ $args ] + Parameter #1 [ ...$args ] + } +} +Foo::method +int(10) +Method [ partial public method method ] { + @@ %s 36 - 36 + + - Parameters [1] { + Parameter #0 [ ...$args ] + } +} +Foo::method +int(100) + diff --git a/Zend/tests/partial_application/magic_002.phpt b/Zend/tests/partial_application/magic_002.phpt index 928f541ce4868..e137c87b7814a 100644 --- a/Zend/tests/partial_application/magic_002.phpt +++ b/Zend/tests/partial_application/magic_002.phpt @@ -5,6 +5,8 @@ Partial application magic: __callStatic class Foo { public static function __callStatic($method, $args) { printf("%s::%s\n", __CLASS__, $method); + + var_dump(...$args); } } @@ -13,13 +15,46 @@ $bar = Foo::method(?); echo (string) new ReflectionFunction($bar); $bar(1); + +$bar = Foo::method(?, ...); + +echo (string) new ReflectionFunction($bar); + +$bar(10); + +$bar = Foo::method(...); + +echo (string) new ReflectionFunction($bar); + +$bar(100); ?> --EXPECTF-- Method [ partial static public method method ] { - @@ %s 8 - 8 + @@ %s 10 - 10 - Parameters [1] { Parameter #0 [ $args ] } } Foo::method +int(1) +Method [ partial static public method method ] { + @@ %s 16 - 16 + + - Parameters [2] { + Parameter #0 [ $args ] + Parameter #1 [ ...$args ] + } +} +Foo::method +int(10) +Method [ partial static public method method ] { + @@ %s 22 - 22 + + - Parameters [1] { + Parameter #0 [ ...$args ] + } +} +Foo::method +int(100) + diff --git a/Zend/zend_partial.c b/Zend/zend_partial.c index e268ffb1684a4..790eb1a5be722 100644 --- a/Zend/zend_partial.c +++ b/Zend/zend_partial.c @@ -147,13 +147,10 @@ static zend_always_inline zend_function* zend_partial_signature_create(zend_part } if (ZEND_PARTIAL_FUNC_FLAG(prototype, ZEND_ACC_VARIADIC)) { - if (ZEND_PARTIAL_IS_CALL_TRAMPOLINE(prototype)) { - memcpy(info, zend_call_magic_arginfo, sizeof(zend_arg_info)); - } else { - memcpy(info, + ZEND_ASSERT(!ZEND_PARTIAL_IS_CALL_TRAMPOLINE(prototype)); + memcpy(info, prototype->common.arg_info + prototype->common.num_args, sizeof(zend_arg_info)); - } num++; } @@ -494,7 +491,7 @@ static zend_always_inline void zend_partial_prototype_overflow(zend_function *fu ZSTR_VAL(function->op_array.filename), function->op_array.line_start); } else { zend_throw_error(NULL, - "not enough arguments for application of %s, %d given and a maximum of %d expected", + "too many arguments for application of %s, %d given and a maximum of %d expected", ZSTR_VAL(symbol), args, expected); } } From 638dc408e3361a74cf745803b2cbdd143f4d7ab9 Mon Sep 17 00:00:00 2001 From: Joe Watkins Date: Sat, 5 Jun 2021 13:34:17 +0200 Subject: [PATCH 03/35] closure bind/call support --- .../variation_bind_001.phpt | 74 +++++++++++++++++++ .../variation_bind_002.phpt | 67 +++++++++++++++++ .../variation_call_001.phpt | 32 ++++++++ .../variation_scope_001.phpt | 18 +++++ Zend/zend_closures.c | 30 +++++--- Zend/zend_partial.c | 60 ++++++++++++--- Zend/zend_partial.h | 4 + 7 files changed, 265 insertions(+), 20 deletions(-) create mode 100644 Zend/tests/partial_application/variation_bind_001.phpt create mode 100644 Zend/tests/partial_application/variation_bind_002.phpt create mode 100644 Zend/tests/partial_application/variation_call_001.phpt create mode 100644 Zend/tests/partial_application/variation_scope_001.phpt diff --git a/Zend/tests/partial_application/variation_bind_001.phpt b/Zend/tests/partial_application/variation_bind_001.phpt new file mode 100644 index 0000000000000..4b064d024ffc4 --- /dev/null +++ b/Zend/tests/partial_application/variation_bind_001.phpt @@ -0,0 +1,74 @@ +--TEST-- +Partial application variation binding +--FILE-- +method(?, new Param); + +$closure(1); + +var_dump($closure); + +$bound = $closure->bindTo(new Foo); + +$bound(1); + +var_dump($bound); +?> +--EXPECTF-- +Bar: 1, Param +object(Closure)#%d (3) { + ["this"]=> + object(Bar)#%d (0) { + } + ["parameter"]=> + array(1) { + ["$a"]=> + string(10) "" + } + ["args"]=> + array(2) { + ["a"]=> + NULL + ["b"]=> + object(Param)#%d (0) { + } + } +} +Foo: 1, Param +object(Closure)#%d (3) { + ["this"]=> + object(Foo)#%d (0) { + } + ["parameter"]=> + array(1) { + ["$a"]=> + string(10) "" + } + ["args"]=> + array(2) { + ["a"]=> + NULL + ["b"]=> + object(Param)#%d (0) { + } + } +} + diff --git a/Zend/tests/partial_application/variation_bind_002.phpt b/Zend/tests/partial_application/variation_bind_002.phpt new file mode 100644 index 0000000000000..ccd3134e2683c --- /dev/null +++ b/Zend/tests/partial_application/variation_bind_002.phpt @@ -0,0 +1,67 @@ +--TEST-- +Partial application variation binding static +--FILE-- +bindTo(null, Foo::class); + +$bound(1); + +var_dump($bound); +?> +--EXPECTF-- +Bar: 1, Param +object(Closure)#%d (2) { + ["parameter"]=> + array(1) { + ["$a"]=> + string(10) "" + } + ["args"]=> + array(2) { + ["a"]=> + NULL + ["b"]=> + object(Param)#%d (0) { + } + } +} +Foo: 1, Param +object(Closure)#%d (2) { + ["parameter"]=> + array(1) { + ["$a"]=> + string(10) "" + } + ["args"]=> + array(2) { + ["a"]=> + NULL + ["b"]=> + object(Param)#%d (0) { + } + } +} + diff --git a/Zend/tests/partial_application/variation_call_001.phpt b/Zend/tests/partial_application/variation_call_001.phpt new file mode 100644 index 0000000000000..099ca9c50fc08 --- /dev/null +++ b/Zend/tests/partial_application/variation_call_001.phpt @@ -0,0 +1,32 @@ +--TEST-- +Partial application variation call +--FILE-- +method(?, new Param); + +$closure(1); + +$closure->call( + new Foo(), 10); +?> +--EXPECT-- +Bar: 1, Param +Foo: 10, Param diff --git a/Zend/tests/partial_application/variation_scope_001.phpt b/Zend/tests/partial_application/variation_scope_001.phpt new file mode 100644 index 0000000000000..afdfba9e920d0 --- /dev/null +++ b/Zend/tests/partial_application/variation_scope_001.phpt @@ -0,0 +1,18 @@ +--TEST-- +Partial application variation called scope +--FILE-- +method(...); + +$bar(); +?> +--EXPECT-- +Foo::method diff --git a/Zend/zend_closures.c b/Zend/zend_closures.c index f352eac4e4df9..6b8df76e92517 100644 --- a/Zend/zend_closures.c +++ b/Zend/zend_closures.c @@ -25,6 +25,7 @@ #include "zend_interfaces.h" #include "zend_objects.h" #include "zend_objects_API.h" +#include "zend_partial.h" #include "zend_globals.h" #include "zend_closures_arginfo.h" @@ -59,8 +60,8 @@ ZEND_METHOD(Closure, __invoke) /* {{{ */ if (!(func->common.fn_flags & ZEND_ACC_TRAMPOLINE_PERMANENT)) { /* destruct the function also, then - we have allocated it in get_method */ - zend_string_release_ex(func->internal_function.function_name, 0); - efree(func); + zend_string_release_ex(func->internal_function.function_name, 0); + efree(func); } #if ZEND_DEBUG execute_data->func = NULL; @@ -73,12 +74,7 @@ static bool zend_valid_closure_binding( { zend_function *func = &closure->func; bool is_fake_closure = (func->common.fn_flags & ZEND_ACC_FAKE_CLOSURE) != 0; - - if (func->common.fn_flags & ZEND_ACC_PARTIAL) { - zend_error(E_WARNING, "Cannot bind an instance to a partial Closure"); - return 0; - } - + if (newthis) { if (func->common.fn_flags & ZEND_ACC_STATIC) { zend_error(E_WARNING, "Cannot bind an instance to a static closure"); @@ -152,7 +148,13 @@ ZEND_METHOD(Closure, call) return; } - if (closure->func.common.fn_flags & ZEND_ACC_GENERATOR) { + if (closure->func.common.fn_flags & ZEND_ACC_PARTIAL) { + zval new_closure; + zend_partial_bind(&new_closure, ZEND_THIS, newthis, newclass); + closure = (zend_closure *) Z_OBJ(new_closure); + fci_cache.function_handler = zend_partial_get_trampoline(Z_OBJ(new_closure)); + newobj = Z_OBJ(new_closure); + } else if (closure->func.common.fn_flags & ZEND_ACC_GENERATOR) { zval new_closure; zend_create_closure(&new_closure, &closure->func, newclass, closure->called_scope, newthis); closure = (zend_closure *) Z_OBJ(new_closure); @@ -193,7 +195,9 @@ ZEND_METHOD(Closure, call) ZVAL_COPY_VALUE(return_value, &closure_result); } - if (fci_cache.function_handler->common.fn_flags & ZEND_ACC_GENERATOR) { + if (!fci_cache.function_handler) { + OBJ_RELEASE(newobj); + } else if (fci_cache.function_handler->common.fn_flags & ZEND_ACC_GENERATOR) { /* copied upon generator creation */ GC_DELREF(&closure->std); } else if (ZEND_USER_CODE(my_function.type) @@ -231,7 +235,11 @@ static void do_closure_bind(zval *return_value, zval *zclosure, zval *newthis, z called_scope = ce; } - zend_create_closure(return_value, &closure->func, ce, called_scope, newthis); + if (closure->func.common.fn_flags & ZEND_ACC_PARTIAL) { + zend_partial_bind(return_value, zclosure, newthis, called_scope); + } else { + zend_create_closure(return_value, &closure->func, ce, called_scope, newthis); + } } /* {{{ Create a closure from another one and bind to another object and scope */ diff --git a/Zend/zend_partial.c b/Zend/zend_partial.c index 790eb1a5be722..18c5168b4b0b8 100644 --- a/Zend/zend_partial.c +++ b/Zend/zend_partial.c @@ -36,8 +36,11 @@ static zend_object_handlers zend_partial_handlers; static zend_arg_info zend_call_magic_arginfo[1]; -#define Z_IS_PLACEHOLDER_ARG_P(p) (Z_TYPE_P(p) == _IS_PLACEHOLDER_ARG) -#define Z_IS_PLACEHOLDER_VARIADIC_P(p) (Z_TYPE_P(p) == _IS_PLACEHOLDER_VARIADIC) +#define Z_IS_PLACEHOLDER_ARG_P(p) \ + (Z_TYPE_P(p) == _IS_PLACEHOLDER_ARG) + +#define Z_IS_PLACEHOLDER_VARIADIC_P(p) \ + (Z_TYPE_P(p) == _IS_PLACEHOLDER_VARIADIC) #define Z_IS_PLACEHOLDER_P(p) \ (Z_IS_PLACEHOLDER_ARG_P(p) || Z_IS_PLACEHOLDER_VARIADIC_P(p)) @@ -359,7 +362,7 @@ static zend_function *zend_partial_get_method(zend_object **object, zend_string } /* }}} */ -static int zend_partial_get_trampoline(zend_object *obj, zend_class_entry **ce_ptr, zend_function **fptr_ptr, zend_object **obj_ptr, bool check_only) +static int zend_partial_get_closure(zend_object *obj, zend_class_entry **ce_ptr, zend_function **fptr_ptr, zend_object **obj_ptr, bool check_only) { zend_partial *partial = (zend_partial*) obj; @@ -369,6 +372,12 @@ static int zend_partial_get_trampoline(zend_object *obj, zend_class_entry **ce_p return SUCCESS; } +zend_function *zend_partial_get_trampoline(zend_object *obj) { + zend_partial *partial = (zend_partial*) obj; + + return &partial->trampoline; +} + static void zend_partial_free(zend_object *object) { zend_partial *partial = (zend_partial*) object; @@ -417,7 +426,7 @@ void zend_partial_startup(void) { zend_partial_handlers.free_obj = zend_partial_free; zend_partial_handlers.get_debug_info = zend_partial_debug; zend_partial_handlers.get_gc = zend_partial_get_gc; - zend_partial_handlers.get_closure = zend_partial_get_trampoline; + zend_partial_handlers.get_closure = zend_partial_get_closure; zend_partial_handlers.get_method = zend_partial_get_method; memset(&zend_call_magic_arginfo, 0, sizeof(zend_arg_info) * 1); @@ -681,9 +690,9 @@ ZEND_NAMED_FUNCTION(zend_partial_call_magic) RETURN_THROWS(); } - if (Z_TYPE(partial->This) == IS_OBJECT) { - object = Z_OBJ(partial->This); - } else if (ZEND_PARTIAL_CALL_FLAG(partial, ZEND_APPLY_FACTORY)) { + fci.size = sizeof(zend_fcall_info); + + if (UNEXPECTED(ZEND_PARTIAL_CALL_FLAG(partial, ZEND_APPLY_FACTORY))) { zend_class_entry *type = Z_CE(partial->This); zval instance; @@ -703,9 +712,14 @@ ZEND_NAMED_FUNCTION(zend_partial_call_magic) } GC_ADD_FLAGS(object, IS_OBJ_DESTRUCTOR_CALLED); + } else { + if (Z_TYPE(partial->This) == IS_OBJECT) { + object = Z_OBJ(partial->This); + } else if (Z_TYPE(partial->This) == IS_UNDEF && Z_CE(partial->This)) { + fcc.called_scope = Z_CE(partial->This); + } } - fci.size = sizeof(zend_fcall_info); fci.retval = return_value; fcc.function_handler = &partial->func; @@ -828,6 +842,8 @@ void zend_partial_create(zval *result, uint32_t info, zval *this_ptr, zend_funct } } + ZEND_PARTIAL_FUNC_ADD(&partial->func, ZEND_ACC_FAKE_CLOSURE); + if (partial->func.type == ZEND_USER_FUNCTION) { zend_string_addref(partial->func.common.function_name); @@ -868,6 +884,32 @@ void zend_partial_create(zval *result, uint32_t info, zval *this_ptr, zend_funct ZEND_ADD_CALL_FLAG(partial, backup_info); } - + zend_partial_trampoline_create(partial, &partial->trampoline); } + +void zend_partial_bind(zval *result, zval *partial, zval *this_ptr, zend_class_entry *scope) { + zval This; + zend_partial *object = (zend_partial*) Z_OBJ_P(partial); + + ZVAL_UNDEF(&This); + + if (!this_ptr || Z_TYPE_P(this_ptr) != IS_OBJECT) { + ZEND_ASSERT(scope && "scope must be set"); + + Z_CE(This) = scope; + } else { + ZVAL_COPY_VALUE(&This, this_ptr); + } + + zend_partial_create(result, ZEND_CALL_INFO(object), &This, + &object->func, object->argc, object->argv, object->named); + + zval *argv = object->argv, + *end = argv + object->argc; + + while (argv < end) { + Z_TRY_ADDREF_P(argv); + argv++; + } +} diff --git a/Zend/zend_partial.h b/Zend/zend_partial.h index d434236457c7d..31d73bbda0413 100644 --- a/Zend/zend_partial.h +++ b/Zend/zend_partial.h @@ -29,8 +29,12 @@ void zend_partial_startup(void); void zend_partial_create(zval *result, uint32_t info, zval *this_ptr, zend_function *function, uint32_t argc, zval *argv, zend_array *extra_named_params); +void zend_partial_bind(zval *result, zval *partial, zval *this_ptr, zend_class_entry *scope); + void zend_partial_args_check(zend_execute_data *call); +zend_function *zend_partial_get_trampoline(zend_object *object); + ZEND_NAMED_FUNCTION(zend_partial_call_magic); END_EXTERN_C() From 4c186881cb7901f2c2c805a48977396246910994 Mon Sep 17 00:00:00 2001 From: Joe Watkins Date: Fri, 11 Jun 2021 14:16:18 +0200 Subject: [PATCH 04/35] fix a couple of bugs --- Zend/zend_partial.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/Zend/zend_partial.c b/Zend/zend_partial.c index 18c5168b4b0b8..ac13bec8449c0 100644 --- a/Zend/zend_partial.c +++ b/Zend/zend_partial.c @@ -130,7 +130,7 @@ static zend_always_inline zend_function* zend_partial_signature_create(zend_part } else { ZEND_ASSERT(0 && "argument out of range"); } - } else if (Z_IS_PLACEHOLDER_VARIADIC_P(arg)) { + } else if (Z_IS_PLACEHOLDER_VARIADIC_P(arg) || Z_ISUNDEF_P(arg)) { if (offset < prototype->common.num_args) { while (offset < prototype->common.num_args) { if ((offset < partial->argc) && @@ -633,9 +633,17 @@ static zend_always_inline uint32_t zend_partial_apply( cStart++; } } else { - ZVAL_COPY_VALUE(fParam, pStart); - pCount++; - fParam++; + if (cStart < cEnd && Z_ISUNDEF_P(pStart)) { + ZVAL_COPY_VALUE(fParam, cStart); + pCount++; + fParam++; + cStart++; + } else { + ZVAL_COPY_VALUE(fParam, pStart); + pCount++; + fParam++; + } + } pStart++; } @@ -895,7 +903,7 @@ void zend_partial_bind(zval *result, zval *partial, zval *this_ptr, zend_class_e ZVAL_UNDEF(&This); if (!this_ptr || Z_TYPE_P(this_ptr) != IS_OBJECT) { - ZEND_ASSERT(scope && "scope must be set"); + ZEND_ASSERT(scope && "scope must be set"); Z_CE(This) = scope; } else { From dcec4f9c98e4500a8455aa188b9ebe2d772fa553 Mon Sep 17 00:00:00 2001 From: Joe Watkins Date: Fri, 11 Jun 2021 14:39:20 +0200 Subject: [PATCH 05/35] fix another bug --- Zend/zend_partial.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Zend/zend_partial.c b/Zend/zend_partial.c index ac13bec8449c0..de0be0e56f1ac 100644 --- a/Zend/zend_partial.c +++ b/Zend/zend_partial.c @@ -131,8 +131,8 @@ static zend_always_inline zend_function* zend_partial_signature_create(zend_part ZEND_ASSERT(0 && "argument out of range"); } } else if (Z_IS_PLACEHOLDER_VARIADIC_P(arg) || Z_ISUNDEF_P(arg)) { - if (offset < prototype->common.num_args) { - while (offset < prototype->common.num_args) { + if (offset < partial->func.common.num_args) { + while (offset < partial->func.common.num_args) { if ((offset < partial->argc) && !Z_IS_PLACEHOLDER_P(&partial->argv[offset]) && !Z_ISUNDEF(partial->argv[offset])) { @@ -142,7 +142,7 @@ static zend_always_inline zend_function* zend_partial_signature_create(zend_part num++; memcpy(info, - &prototype->common.arg_info[offset], + &partial->func.common.arg_info[offset], sizeof(zend_arg_info)); ZEND_TYPE_FULL_MASK(info->type) &= ~_ZEND_IS_VARIADIC_BIT; info++; @@ -643,7 +643,6 @@ static zend_always_inline uint32_t zend_partial_apply( pCount++; fParam++; } - } pStart++; } From e29da6f76ebb3a837684f9124848dbe3ebf29b91 Mon Sep 17 00:00:00 2001 From: Joe Watkins Date: Fri, 11 Jun 2021 16:25:10 +0200 Subject: [PATCH 06/35] I need a break --- Zend/zend_partial.c | 1 + 1 file changed, 1 insertion(+) diff --git a/Zend/zend_partial.c b/Zend/zend_partial.c index de0be0e56f1ac..1feaca6508482 100644 --- a/Zend/zend_partial.c +++ b/Zend/zend_partial.c @@ -172,6 +172,7 @@ static zend_always_inline zend_function* zend_partial_signature_create(zend_part sizeof(zend_arg_info)); } info++; + break; } } From 216c1018610834e30b26231729af748f49521e43 Mon Sep 17 00:00:00 2001 From: Joe Watkins Date: Sat, 12 Jun 2021 10:06:35 +0200 Subject: [PATCH 07/35] fix an asan error, and an off by one --- Zend/zend_partial.c | 20 +++++++++----------- Zend/zend_partial.h | 2 +- Zend/zend_vm_def.h | 15 +++++++++------ Zend/zend_vm_execute.h | 13 ++++++++----- 4 files changed, 27 insertions(+), 23 deletions(-) diff --git a/Zend/zend_partial.c b/Zend/zend_partial.c index 1feaca6508482..f19e74cbef952 100644 --- a/Zend/zend_partial.c +++ b/Zend/zend_partial.c @@ -96,10 +96,6 @@ static zend_always_inline zend_function* zend_partial_signature_create(zend_part uint32_t offset = 0, num = 0, required = 0, limit = partial->argc; - if (ZEND_PARTIAL_CALL_FLAG(partial, ZEND_APPLY_VARIADIC)) { - limit++; - } - ZEND_PARTIAL_FUNC_DEL(&partial->prototype, ZEND_ACC_VARIADIC); while (offset < limit) { @@ -154,11 +150,11 @@ static zend_always_inline zend_function* zend_partial_signature_create(zend_part memcpy(info, prototype->common.arg_info + prototype->common.num_args, sizeof(zend_arg_info)); - num++; - } - if (ZEND_TYPE_FULL_MASK(info->type) & _ZEND_IS_VARIADIC_BIT) { - ZEND_PARTIAL_FUNC_ADD(&partial->prototype, ZEND_ACC_VARIADIC); + if (ZEND_TYPE_FULL_MASK(info->type) & _ZEND_IS_VARIADIC_BIT) { + ZEND_PARTIAL_FUNC_ADD(&partial->prototype, ZEND_ACC_VARIADIC); + } + num++; } break; } else if (ZEND_PARTIAL_FUNC_FLAG(prototype, ZEND_ACC_VARIADIC)) { @@ -784,8 +780,9 @@ ZEND_NAMED_FUNCTION(zend_partial_call_magic) efree(fci.params); } -void zend_partial_create(zval *result, uint32_t info, zval *this_ptr, zend_function *function, uint32_t argc, zval *argv, zend_array *extra_named_params) { +bool zend_partial_create(zval *result, uint32_t info, zval *this_ptr, zend_function *function, uint32_t argc, zval *argv, zend_array *extra_named_params) { zend_function *prototype = NULL; + bool zend_release_trampoline = false; ZVAL_OBJ(result, zend_partial_new(zend_ce_closure, info)); @@ -878,8 +875,7 @@ void zend_partial_create(zval *result, uint32_t info, zval *this_ptr, zend_funct ZSTR_KNOWN(ZEND_STR_MAGIC_INVOKE))) { This = this_ptr; if (!ZEND_PARTIAL_FUNC_FLAG(function, ZEND_ACC_TRAMPOLINE_PERMANENT)) { - EG(trampoline).common.function_name = NULL; - efree(function); + zend_release_trampoline = true; } } else { This = zend_get_closure_this_ptr(this_ptr); @@ -894,6 +890,8 @@ void zend_partial_create(zval *result, uint32_t info, zval *this_ptr, zend_funct } zend_partial_trampoline_create(partial, &partial->trampoline); + + return zend_release_trampoline; } void zend_partial_bind(zval *result, zval *partial, zval *this_ptr, zend_class_entry *scope) { diff --git a/Zend/zend_partial.h b/Zend/zend_partial.h index 31d73bbda0413..357a3a5a7c9de 100644 --- a/Zend/zend_partial.h +++ b/Zend/zend_partial.h @@ -27,7 +27,7 @@ void zend_partial_startup(void); #define ZEND_APPLY_PASS (1<<18) #define ZEND_APPLY_VARIADIC (1<<19) -void zend_partial_create(zval *result, uint32_t info, zval *this_ptr, zend_function *function, uint32_t argc, zval *argv, zend_array *extra_named_params); +bool zend_partial_create(zval *result, uint32_t info, zval *this_ptr, zend_function *function, uint32_t argc, zval *argv, zend_array *extra_named_params); void zend_partial_bind(zval *result, zval *partial, zval *this_ptr, zend_class_entry *scope); diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index c0575d330a2ec..033a80848156b 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -8793,6 +8793,7 @@ ZEND_VM_HANDLER(203, ZEND_DO_FCALL_PARTIAL, ANY, ANY) zend_execute_data *call = EX(call); zval *result = NULL; uint32_t info = ZEND_APPLY_NORMAL; + bool zend_do_release_trampoline = false; if (opline->op1_type != IS_UNUSED) { result = EX_VAR(opline->op1.var); @@ -8811,9 +8812,10 @@ ZEND_VM_HANDLER(203, ZEND_DO_FCALL_PARTIAL, ANY, ANY) } if (result) { - zend_partial_create(result, info, &call->This, call->func, + zend_do_release_trampoline = zend_partial_create(result, info, + &call->This, call->func, ZEND_CALL_NUM_ARGS(call), ZEND_CALL_ARG(call, 1), - ZEND_CALL_INFO(call) & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS ? + ZEND_CALL_INFO(call) & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS ? call->extra_named_params : NULL); if (info & ZEND_APPLY_FACTORY) { @@ -8821,10 +8823,6 @@ ZEND_VM_HANDLER(203, ZEND_DO_FCALL_PARTIAL, ANY, ANY) OBJ_RELEASE(Z_OBJ(call->This)); } } - - if (call->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) { - zend_free_trampoline(call->func); - } if (ZEND_CALL_INFO(call) & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS) { zend_array_release(call->extra_named_params); @@ -8836,6 +8834,11 @@ ZEND_VM_HANDLER(203, ZEND_DO_FCALL_PARTIAL, ANY, ANY) OBJ_RELEASE(ZEND_CLOSURE_OBJECT(call->func)); } + if (zend_do_release_trampoline) { + EG(trampoline).common.function_name = NULL; + efree(call->func); + } + EX(call) = call->prev_execute_data; zend_vm_stack_free_call_frame(call); diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index bccccc105766b..991b05c963e1e 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -3513,6 +3513,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_PARTIAL_SPEC_HANDLER( zend_execute_data *call = EX(call); zval *result = NULL; uint32_t info = ZEND_APPLY_NORMAL; + bool zend_do_release_trampoline = false; if (opline->op1_type != IS_UNUSED) { result = EX_VAR(opline->op1.var); @@ -3531,7 +3532,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_PARTIAL_SPEC_HANDLER( } if (result) { - zend_partial_create(result, info, &call->This, call->func, + zend_do_release_trampoline = zend_partial_create(result, info, + &call->This, call->func, ZEND_CALL_NUM_ARGS(call), ZEND_CALL_ARG(call, 1), ZEND_CALL_INFO(call) & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS ? call->extra_named_params : NULL); @@ -3542,10 +3544,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_PARTIAL_SPEC_HANDLER( } } - if (call->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) { - zend_free_trampoline(call->func); - } - if (ZEND_CALL_INFO(call) & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS) { zend_array_release(call->extra_named_params); } @@ -3556,6 +3554,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_PARTIAL_SPEC_HANDLER( OBJ_RELEASE(ZEND_CLOSURE_OBJECT(call->func)); } + if (zend_do_release_trampoline) { + EG(trampoline).common.function_name = NULL; + efree(call->func); + } + EX(call) = call->prev_execute_data; zend_vm_stack_free_call_frame(call); From 6bd2f25e77c0e044b6e3a9b028b4bd88090b5fee Mon Sep 17 00:00:00 2001 From: Joe Watkins Date: Wed, 16 Jun 2021 15:48:06 +0200 Subject: [PATCH 08/35] a test, and fix --- .../variation_variadics_007.phpt | 14 ++++++++++++++ Zend/zend_partial.c | 15 +++++++-------- 2 files changed, 21 insertions(+), 8 deletions(-) create mode 100644 Zend/tests/partial_application/variation_variadics_007.phpt diff --git a/Zend/tests/partial_application/variation_variadics_007.phpt b/Zend/tests/partial_application/variation_variadics_007.phpt new file mode 100644 index 0000000000000..8b5c1d059972e --- /dev/null +++ b/Zend/tests/partial_application/variation_variadics_007.phpt @@ -0,0 +1,14 @@ +--TEST-- +Partial application variation extra through variadic +--FILE-- + $a + $b)); +?> +--EXPECT-- +int(3) diff --git a/Zend/zend_partial.c b/Zend/zend_partial.c index f19e74cbef952..35164c6e005f5 100644 --- a/Zend/zend_partial.c +++ b/Zend/zend_partial.c @@ -124,7 +124,7 @@ static zend_always_inline zend_function* zend_partial_signature_create(zend_part ZEND_TYPE_FULL_MASK(info->type) &= ~_ZEND_IS_VARIADIC_BIT; info++; } else { - ZEND_ASSERT(0 && "argument out of range"); + break; } } else if (Z_IS_PLACEHOLDER_VARIADIC_P(arg) || Z_ISUNDEF_P(arg)) { if (offset < partial->func.common.num_args) { @@ -546,15 +546,14 @@ void zend_partial_args_check(zend_execute_data *call) { /* this is invoked by VM before the creation of zend_partial */ zend_function *function = call->func; - uint32_t num = ZEND_CALL_NUM_ARGS(call) + - ((ZEND_CALL_INFO(call) & ZEND_CALL_VARIADIC_PLACEHOLDER) ? -1 : 0); + /* this check is delayed in the case of variadic application */ + if (ZEND_PARTIAL_CALL_FLAG(call, ZEND_CALL_VARIADIC_PLACEHOLDER)) { + return; + } + uint32_t num = ZEND_CALL_NUM_ARGS(call); + if (num < function->common.required_num_args) { - /* this check is delayed in the case of variadic application */ - if (ZEND_PARTIAL_CALL_FLAG(call, ZEND_CALL_VARIADIC_PLACEHOLDER)) { - return; - } - zend_string *symbol = zend_partial_symbol_name(call, function); zend_partial_args_underflow( function, symbol, From 4f4e6de3d7ab02c78c02601cbe1434e932306585 Mon Sep 17 00:00:00 2001 From: Joe Watkins Date: Thu, 17 Jun 2021 15:14:54 +0200 Subject: [PATCH 09/35] fix place holder -> placeholder --- Zend/tests/partial_application/compile_errors_001.phpt | 2 +- Zend/tests/partial_application/compile_errors_002.phpt | 2 +- Zend/tests/partial_application/compile_errors_003.phpt | 4 ++-- Zend/tests/partial_application/compile_errors_004.phpt | 4 ++-- Zend/tests/partial_application/compile_errors_005.phpt | 2 +- Zend/tests/partial_application/compile_errors_006.phpt | 2 +- Zend/tests/partial_application/compile_errors_007.phpt | 2 +- Zend/tests/partial_application/errors_001.phpt | 10 +++++----- Zend/tests/partial_application/errors_002.phpt | 4 ++-- Zend/tests/partial_application/variation_pass_001.phpt | 2 +- .../partial_application/variation_variadics_003.phpt | 2 +- .../partial_application/variation_variadics_006.phpt | 2 +- Zend/zend_compile.c | 10 +++++----- Zend/zend_execute.c | 4 ++-- Zend/zend_partial.c | 4 ++-- 15 files changed, 28 insertions(+), 28 deletions(-) diff --git a/Zend/tests/partial_application/compile_errors_001.phpt b/Zend/tests/partial_application/compile_errors_001.phpt index 8d5587851d500..73eafa4e2cd45 100644 --- a/Zend/tests/partial_application/compile_errors_001.phpt +++ b/Zend/tests/partial_application/compile_errors_001.phpt @@ -5,5 +5,5 @@ Partial application compile errors: multiple ... foo(..., ...); ?> --EXPECTF-- -Fatal error: Variadic place holder may only appear once in %s on line %d +Fatal error: Variadic placeholder may only appear once in %s on line %d diff --git a/Zend/tests/partial_application/compile_errors_002.phpt b/Zend/tests/partial_application/compile_errors_002.phpt index 4f5d2a552af29..29a346ec88a5f 100644 --- a/Zend/tests/partial_application/compile_errors_002.phpt +++ b/Zend/tests/partial_application/compile_errors_002.phpt @@ -5,5 +5,5 @@ Partial application compile errors: only named arguments after ... foo(..., ?); ?> --EXPECTF-- -Fatal error: Only named arguments may follow variadic place holder in %s on line %d +Fatal error: Only named arguments may follow variadic placeholder in %s on line %d diff --git a/Zend/tests/partial_application/compile_errors_003.phpt b/Zend/tests/partial_application/compile_errors_003.phpt index 16596a38839dc..6d833b7ef1b61 100644 --- a/Zend/tests/partial_application/compile_errors_003.phpt +++ b/Zend/tests/partial_application/compile_errors_003.phpt @@ -1,9 +1,9 @@ --TEST-- -Partial application compile errors: named arguments must come after place holder +Partial application compile errors: named arguments must come after placeholder --FILE-- --EXPECTF-- -Fatal error: Named arguments must come after all place holders in %s on line %d +Fatal error: Named arguments must come after all placeholders in %s on line %d diff --git a/Zend/tests/partial_application/compile_errors_004.phpt b/Zend/tests/partial_application/compile_errors_004.phpt index 91cb3af63c042..efd544282c2e9 100644 --- a/Zend/tests/partial_application/compile_errors_004.phpt +++ b/Zend/tests/partial_application/compile_errors_004.phpt @@ -1,8 +1,8 @@ --TEST-- -Partial application compile errors: named arguments must come after variadic place holder +Partial application compile errors: named arguments must come after variadic placeholder --FILE-- --EXPECTF-- -Fatal error: Named arguments must come after all place holders in %s on line %d +Fatal error: Named arguments must come after all placeholders in %s on line %d diff --git a/Zend/tests/partial_application/compile_errors_005.phpt b/Zend/tests/partial_application/compile_errors_005.phpt index 3073eda24d479..b6a898008617b 100644 --- a/Zend/tests/partial_application/compile_errors_005.phpt +++ b/Zend/tests/partial_application/compile_errors_005.phpt @@ -5,5 +5,5 @@ Partial application compile errors: follow variadic with un-named arg foo(..., $a); ?> --EXPECTF-- -Fatal error: Only named arguments may follow variadic place holder in %s on line %d +Fatal error: Only named arguments may follow variadic placeholder in %s on line %d diff --git a/Zend/tests/partial_application/compile_errors_006.phpt b/Zend/tests/partial_application/compile_errors_006.phpt index 5f240afa1135f..21ad1a954e929 100644 --- a/Zend/tests/partial_application/compile_errors_006.phpt +++ b/Zend/tests/partial_application/compile_errors_006.phpt @@ -1,5 +1,5 @@ --TEST-- -Partial application compile errors: mix application with unpack (place holder after) +Partial application compile errors: mix application with unpack (placeholder after) --FILE-- "bar"], ...); diff --git a/Zend/tests/partial_application/compile_errors_007.phpt b/Zend/tests/partial_application/compile_errors_007.phpt index 765d44dcfd58a..5cc881ebf60f5 100644 --- a/Zend/tests/partial_application/compile_errors_007.phpt +++ b/Zend/tests/partial_application/compile_errors_007.phpt @@ -1,5 +1,5 @@ --TEST-- -Partial application compile errors: mix application with unpack (place holder before) +Partial application compile errors: mix application with unpack (placeholder before) --FILE-- "bar"]); diff --git a/Zend/tests/partial_application/errors_001.phpt b/Zend/tests/partial_application/errors_001.phpt index e709ba207c489..705d5af4cde66 100644 --- a/Zend/tests/partial_application/errors_001.phpt +++ b/Zend/tests/partial_application/errors_001.phpt @@ -1,5 +1,5 @@ --TEST-- -Partial application errors: place holder count errors +Partial application errors: placeholder count errors --FILE-- --EXPECTF-- -not enough arguments and or place holders for application of foo, 1 given and exactly 3 expected, declared in %s on line 2 -too many arguments and or place holders for application of foo, 4 given and a maximum of 3 expected, declared in %s on line 2 -not enough arguments and or place holders for application of property_exists, 1 given and exactly 2 expected -too many arguments and or place holders for application of usleep, 2 given and a maximum of 1 expected +not enough arguments and or placeholders for application of foo, 1 given and exactly 3 expected, declared in %s on line 2 +too many arguments and or placeholders for application of foo, 4 given and a maximum of 3 expected, declared in %s on line 2 +not enough arguments and or placeholders for application of property_exists, 1 given and exactly 2 expected +too many arguments and or placeholders for application of usleep, 2 given and a maximum of 1 expected diff --git a/Zend/tests/partial_application/errors_002.phpt b/Zend/tests/partial_application/errors_002.phpt index 88e7a7ba8f87a..2f852348fb1fd 100644 --- a/Zend/tests/partial_application/errors_002.phpt +++ b/Zend/tests/partial_application/errors_002.phpt @@ -1,5 +1,5 @@ --TEST-- -Partial application errors: named parameter overwrites place holder +Partial application errors: named parameter overwrites placeholder --FILE-- --EXPECT-- -Named parameter $a overwrites previous place holder +Named parameter $a overwrites previous placeholder diff --git a/Zend/tests/partial_application/variation_pass_001.phpt b/Zend/tests/partial_application/variation_pass_001.phpt index 98a92162ac52e..c31d0fcb2470d 100644 --- a/Zend/tests/partial_application/variation_pass_001.phpt +++ b/Zend/tests/partial_application/variation_pass_001.phpt @@ -11,4 +11,4 @@ try { } ?> --EXPECT-- -too many arguments and or place holders for application of Foo::__construct, 1 given and a maximum of 0 expected +too many arguments and or placeholders for application of Foo::__construct, 1 given and a maximum of 0 expected diff --git a/Zend/tests/partial_application/variation_variadics_003.phpt b/Zend/tests/partial_application/variation_variadics_003.phpt index b70c4b77d69f3..0631f7beb5e76 100644 --- a/Zend/tests/partial_application/variation_variadics_003.phpt +++ b/Zend/tests/partial_application/variation_variadics_003.phpt @@ -38,7 +38,7 @@ $foo(1, 2, 3); // OK ?> --EXPECTF-- too many arguments for application of foo, 3 given and a maximum of 2 expected, declared in %s on line %d -too many arguments and or place holders for application of foo, 3 given and a maximum of 2 expected, declared in %s on line %d +too many arguments and or placeholders for application of foo, 3 given and a maximum of 2 expected, declared in %s on line %d too many arguments for application of bar, 3 given and a maximum of 2 expected, declared in %s on line %d array(3) { [0]=> diff --git a/Zend/tests/partial_application/variation_variadics_006.phpt b/Zend/tests/partial_application/variation_variadics_006.phpt index d60de988db4d9..923bddcbe18f6 100644 --- a/Zend/tests/partial_application/variation_variadics_006.phpt +++ b/Zend/tests/partial_application/variation_variadics_006.phpt @@ -1,5 +1,5 @@ --TEST-- -Partial application variation named may overwrite variadic place holder +Partial application variation named may overwrite variadic placeholder --FILE-- attr == _IS_PLACEHOLDER_VARIADIC) { if (uses_named_args) { zend_error_noreturn(E_COMPILE_ERROR, - "Named arguments must come after all place holders"); + "Named arguments must come after all placeholders"); } if (uses_variadic_placeholder) { zend_error_noreturn(E_COMPILE_ERROR, - "Variadic place holder may only appear once"); + "Variadic placeholder may only appear once"); } uses_variadic_placeholder = 1; } else if (arg->attr == _IS_PLACEHOLDER_ARG) { if (uses_named_args) { zend_error_noreturn(E_COMPILE_ERROR, - "Named arguments must come after all place holders"); + "Named arguments must come after all placeholders"); } if (uses_variadic_placeholder) { zend_error_noreturn(E_COMPILE_ERROR, - "Only named arguments may follow variadic place holder"); + "Only named arguments may follow variadic placeholder"); } } @@ -3576,7 +3576,7 @@ uint32_t zend_compile_args( if (uses_variadic_placeholder) { zend_error_noreturn(E_COMPILE_ERROR, - "Only named arguments may follow variadic place holder"); + "Only named arguments may follow variadic placeholder"); } arg_count++; diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index cf2be7434e75f..b6ad8e736d103 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -4480,7 +4480,7 @@ zval * ZEND_FASTCALL zend_handle_named_arg( arg = zend_hash_add_empty_element(call->extra_named_params, arg_name); if (!arg) { zend_throw_error(NULL, "Named parameter $%s overwrites previous %s", - ZSTR_VAL(arg_name), Z_TYPE_P(arg) == _IS_PLACEHOLDER_ARG ? "place holder" : "argument"); + ZSTR_VAL(arg_name), Z_TYPE_P(arg) == _IS_PLACEHOLDER_ARG ? "placeholder" : "argument"); return NULL; } *arg_num_ptr = arg_offset + 1; @@ -4516,7 +4516,7 @@ zval * ZEND_FASTCALL zend_handle_named_arg( if (UNEXPECTED(!Z_ISUNDEF_P(arg))) { zend_throw_error(NULL, "Named parameter $%s overwrites previous %s", - ZSTR_VAL(arg_name), Z_TYPE_P(arg) == _IS_PLACEHOLDER_ARG ? "place holder" : "argument"); + ZSTR_VAL(arg_name), Z_TYPE_P(arg) == _IS_PLACEHOLDER_ARG ? "placeholder" : "argument"); return NULL; } } diff --git a/Zend/zend_partial.c b/Zend/zend_partial.c index 35164c6e005f5..9fda5a82c0bc6 100644 --- a/Zend/zend_partial.c +++ b/Zend/zend_partial.c @@ -504,7 +504,7 @@ static zend_always_inline void zend_partial_prototype_overflow(zend_function *fu static zend_always_inline void zend_partial_args_underflow(zend_function *function, zend_string *symbol, uint32_t args, uint32_t expected, bool calling, bool prototype) { const char *what = calling ? - "arguments" : "arguments and or place holders"; + "arguments" : "arguments and or placeholders"; const char *from = prototype ? "application" : "implementation"; const char *limit = function->common.num_args <= function->common.required_num_args ? @@ -525,7 +525,7 @@ static zend_always_inline void zend_partial_args_underflow(zend_function *functi static zend_always_inline void zend_partial_args_overflow(zend_function *function, zend_string *symbol, uint32_t args, uint32_t expected, bool calling, bool prototype) { const char *what = calling ? - "arguments" : "arguments and or place holders"; + "arguments" : "arguments and or placeholders"; const char *from = prototype ? "application" : "implementation"; From 003ecbe9d66dc3fc426139b83955306c974bf471 Mon Sep 17 00:00:00 2001 From: Joe Watkins Date: Thu, 17 Jun 2021 15:22:31 +0200 Subject: [PATCH 10/35] fix inconsistency --- .../variation_variadics_007.phpt | 2 +- Zend/zend_partial.c | 13 +++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Zend/tests/partial_application/variation_variadics_007.phpt b/Zend/tests/partial_application/variation_variadics_007.phpt index 8b5c1d059972e..1688112787ad8 100644 --- a/Zend/tests/partial_application/variation_variadics_007.phpt +++ b/Zend/tests/partial_application/variation_variadics_007.phpt @@ -2,7 +2,7 @@ Partial application variation extra through variadic --FILE-- func; - - /* this check is delayed in the case of variadic application */ - if (ZEND_PARTIAL_CALL_FLAG(call, ZEND_CALL_VARIADIC_PLACEHOLDER)) { - return; - } - uint32_t num = ZEND_CALL_NUM_ARGS(call); + uint32_t num = ZEND_CALL_NUM_ARGS(call) + + (ZEND_PARTIAL_CALL_FLAG(call, ZEND_CALL_VARIADIC_PLACEHOLDER) ? -1 : 0); if (num < function->common.required_num_args) { + /* this check is delayed in the case of variadic application */ + if (ZEND_PARTIAL_CALL_FLAG(call, ZEND_CALL_VARIADIC_PLACEHOLDER)) { + return; + } + zend_string *symbol = zend_partial_symbol_name(call, function); zend_partial_args_underflow( function, symbol, From 800be73312361cd805ce49871acf5be62a4b3d19 Mon Sep 17 00:00:00 2001 From: Joe Watkins Date: Thu, 17 Jun 2021 15:35:00 +0200 Subject: [PATCH 11/35] fix magic assertion failure where result is unused --- Zend/tests/partial_application/magic_003.phpt | 13 +++++++++++++ Zend/zend_vm_def.h | 6 ++++-- Zend/zend_vm_execute.h | 6 ++++-- 3 files changed, 21 insertions(+), 4 deletions(-) create mode 100644 Zend/tests/partial_application/magic_003.phpt diff --git a/Zend/tests/partial_application/magic_003.phpt b/Zend/tests/partial_application/magic_003.phpt new file mode 100644 index 0000000000000..185c71f81f6ed --- /dev/null +++ b/Zend/tests/partial_application/magic_003.phpt @@ -0,0 +1,13 @@ +--TEST-- +Partial application magic trampoline release +--FILE-- + +--EXPECT-- +OK diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 033a80848156b..90fa806fd403a 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -8822,6 +8822,9 @@ ZEND_VM_HANDLER(203, ZEND_DO_FCALL_PARTIAL, ANY, ANY) GC_ADD_FLAGS(Z_OBJ(call->This), IS_OBJ_DESTRUCTOR_CALLED); OBJ_RELEASE(Z_OBJ(call->This)); } + } else if ((call->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) && + !(call->func->common.fn_flags & ZEND_ACC_TRAMPOLINE_PERMANENT)) { + zend_do_release_trampoline = true; } if (ZEND_CALL_INFO(call) & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS) { @@ -8835,8 +8838,7 @@ ZEND_VM_HANDLER(203, ZEND_DO_FCALL_PARTIAL, ANY, ANY) } if (zend_do_release_trampoline) { - EG(trampoline).common.function_name = NULL; - efree(call->func); + zend_free_trampoline(call->func); } EX(call) = call->prev_execute_data; diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 991b05c963e1e..3ce075edf92fc 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -3542,6 +3542,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_PARTIAL_SPEC_HANDLER( GC_ADD_FLAGS(Z_OBJ(call->This), IS_OBJ_DESTRUCTOR_CALLED); OBJ_RELEASE(Z_OBJ(call->This)); } + } else if ((call->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) && + !(call->func->common.fn_flags & ZEND_ACC_TRAMPOLINE_PERMANENT)) { + zend_do_release_trampoline = true; } if (ZEND_CALL_INFO(call) & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS) { @@ -3555,8 +3558,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_PARTIAL_SPEC_HANDLER( } if (zend_do_release_trampoline) { - EG(trampoline).common.function_name = NULL; - efree(call->func); + zend_free_trampoline(call->func); } EX(call) = call->prev_execute_data; From f7863f4d11440fe6b6d68ba18005d60eb846bb1e Mon Sep 17 00:00:00 2001 From: Joe Watkins Date: Thu, 17 Jun 2021 15:45:47 +0200 Subject: [PATCH 12/35] collect argv --- .../partial_application/variation_gc_002.phpt | 11 ++++++++++ Zend/zend_partial.c | 20 +++++++++++++++++-- 2 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 Zend/tests/partial_application/variation_gc_002.phpt diff --git a/Zend/tests/partial_application/variation_gc_002.phpt b/Zend/tests/partial_application/variation_gc_002.phpt new file mode 100644 index 0000000000000..5f00705cf79b8 --- /dev/null +++ b/Zend/tests/partial_application/variation_gc_002.phpt @@ -0,0 +1,11 @@ +--TEST-- +Partial application variation GC +--FILE-- +prop = var_dump($obj, ?); + +echo "OK"; +?> +--EXPECT-- +OK diff --git a/Zend/zend_partial.c b/Zend/zend_partial.c index 91737e2354eed..915435ca2a4d4 100644 --- a/Zend/zend_partial.c +++ b/Zend/zend_partial.c @@ -341,8 +341,24 @@ static HashTable *zend_partial_get_gc(zend_object *obj, zval **table, int *n) { zend_partial *partial = (zend_partial *)obj; - *table = Z_TYPE(partial->This) == IS_OBJECT ? &partial->This : NULL; - *n = Z_TYPE(partial->This) == IS_OBJECT ? 1 : 0; + if (!partial->argc) { + *table = Z_TYPE(partial->This) == IS_OBJECT ? &partial->This : NULL; + *n = Z_TYPE(partial->This) == IS_OBJECT ? 1 : 0; + } else { + zend_get_gc_buffer *buffer = zend_get_gc_buffer_create(); + + if (Z_TYPE(partial->This) == IS_OBJECT) { + zend_get_gc_buffer_add_zval(buffer, &partial->This); + } + + for (uint32_t arg = 0; arg < partial->argc; arg++) { + if (Z_OPT_REFCOUNTED(partial->argv[arg])) { + zend_get_gc_buffer_add_zval(buffer, &partial->argv[arg]); + } + } + + zend_get_gc_buffer_use(buffer, table, n); + } return NULL; } From 004166ff3fe42900c0e90a0d2dec1bf9cdb13af2 Mon Sep 17 00:00:00 2001 From: Joe Watkins Date: Thu, 17 Jun 2021 15:54:20 +0200 Subject: [PATCH 13/35] used/unused trampoline test --- Zend/tests/partial_application/magic_003.phpt | 2 +- Zend/tests/partial_application/magic_004.phpt | 13 +++++++++++++ Zend/zend_partial.c | 8 +------- Zend/zend_partial.h | 2 +- Zend/zend_vm_def.h | 11 ++++------- Zend/zend_vm_execute.h | 11 ++++------- 6 files changed, 24 insertions(+), 23 deletions(-) create mode 100644 Zend/tests/partial_application/magic_004.phpt diff --git a/Zend/tests/partial_application/magic_003.phpt b/Zend/tests/partial_application/magic_003.phpt index 185c71f81f6ed..a46fb5df226bf 100644 --- a/Zend/tests/partial_application/magic_003.phpt +++ b/Zend/tests/partial_application/magic_003.phpt @@ -1,5 +1,5 @@ --TEST-- -Partial application magic trampoline release +Partial application magic trampoline release unused --FILE-- +--EXPECT-- +OK diff --git a/Zend/zend_partial.c b/Zend/zend_partial.c index 915435ca2a4d4..27fc12dab2dd5 100644 --- a/Zend/zend_partial.c +++ b/Zend/zend_partial.c @@ -796,9 +796,8 @@ ZEND_NAMED_FUNCTION(zend_partial_call_magic) efree(fci.params); } -bool zend_partial_create(zval *result, uint32_t info, zval *this_ptr, zend_function *function, uint32_t argc, zval *argv, zend_array *extra_named_params) { +void zend_partial_create(zval *result, uint32_t info, zval *this_ptr, zend_function *function, uint32_t argc, zval *argv, zend_array *extra_named_params) { zend_function *prototype = NULL; - bool zend_release_trampoline = false; ZVAL_OBJ(result, zend_partial_new(zend_ce_closure, info)); @@ -890,9 +889,6 @@ bool zend_partial_create(zval *result, uint32_t info, zval *this_ptr, zend_funct partial->func.common.function_name, ZSTR_KNOWN(ZEND_STR_MAGIC_INVOKE))) { This = this_ptr; - if (!ZEND_PARTIAL_FUNC_FLAG(function, ZEND_ACC_TRAMPOLINE_PERMANENT)) { - zend_release_trampoline = true; - } } else { This = zend_get_closure_this_ptr(this_ptr); } @@ -906,8 +902,6 @@ bool zend_partial_create(zval *result, uint32_t info, zval *this_ptr, zend_funct } zend_partial_trampoline_create(partial, &partial->trampoline); - - return zend_release_trampoline; } void zend_partial_bind(zval *result, zval *partial, zval *this_ptr, zend_class_entry *scope) { diff --git a/Zend/zend_partial.h b/Zend/zend_partial.h index 357a3a5a7c9de..31d73bbda0413 100644 --- a/Zend/zend_partial.h +++ b/Zend/zend_partial.h @@ -27,7 +27,7 @@ void zend_partial_startup(void); #define ZEND_APPLY_PASS (1<<18) #define ZEND_APPLY_VARIADIC (1<<19) -bool zend_partial_create(zval *result, uint32_t info, zval *this_ptr, zend_function *function, uint32_t argc, zval *argv, zend_array *extra_named_params); +void zend_partial_create(zval *result, uint32_t info, zval *this_ptr, zend_function *function, uint32_t argc, zval *argv, zend_array *extra_named_params); void zend_partial_bind(zval *result, zval *partial, zval *this_ptr, zend_class_entry *scope); diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 90fa806fd403a..53132025e238d 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -8793,7 +8793,6 @@ ZEND_VM_HANDLER(203, ZEND_DO_FCALL_PARTIAL, ANY, ANY) zend_execute_data *call = EX(call); zval *result = NULL; uint32_t info = ZEND_APPLY_NORMAL; - bool zend_do_release_trampoline = false; if (opline->op1_type != IS_UNUSED) { result = EX_VAR(opline->op1.var); @@ -8812,7 +8811,7 @@ ZEND_VM_HANDLER(203, ZEND_DO_FCALL_PARTIAL, ANY, ANY) } if (result) { - zend_do_release_trampoline = zend_partial_create(result, info, + zend_partial_create(result, info, &call->This, call->func, ZEND_CALL_NUM_ARGS(call), ZEND_CALL_ARG(call, 1), ZEND_CALL_INFO(call) & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS ? @@ -8822,9 +8821,6 @@ ZEND_VM_HANDLER(203, ZEND_DO_FCALL_PARTIAL, ANY, ANY) GC_ADD_FLAGS(Z_OBJ(call->This), IS_OBJ_DESTRUCTOR_CALLED); OBJ_RELEASE(Z_OBJ(call->This)); } - } else if ((call->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) && - !(call->func->common.fn_flags & ZEND_ACC_TRAMPOLINE_PERMANENT)) { - zend_do_release_trampoline = true; } if (ZEND_CALL_INFO(call) & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS) { @@ -8837,8 +8833,9 @@ ZEND_VM_HANDLER(203, ZEND_DO_FCALL_PARTIAL, ANY, ANY) OBJ_RELEASE(ZEND_CLOSURE_OBJECT(call->func)); } - if (zend_do_release_trampoline) { - zend_free_trampoline(call->func); + if ((call->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) && + !(call->func->common.fn_flags & ZEND_ACC_TRAMPOLINE_PERMANENT)) { + zend_free_trampoline(call->func); } EX(call) = call->prev_execute_data; diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 3ce075edf92fc..c239ddd53f1a6 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -3513,7 +3513,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_PARTIAL_SPEC_HANDLER( zend_execute_data *call = EX(call); zval *result = NULL; uint32_t info = ZEND_APPLY_NORMAL; - bool zend_do_release_trampoline = false; if (opline->op1_type != IS_UNUSED) { result = EX_VAR(opline->op1.var); @@ -3532,7 +3531,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_PARTIAL_SPEC_HANDLER( } if (result) { - zend_do_release_trampoline = zend_partial_create(result, info, + zend_partial_create(result, info, &call->This, call->func, ZEND_CALL_NUM_ARGS(call), ZEND_CALL_ARG(call, 1), ZEND_CALL_INFO(call) & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS ? @@ -3542,9 +3541,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_PARTIAL_SPEC_HANDLER( GC_ADD_FLAGS(Z_OBJ(call->This), IS_OBJ_DESTRUCTOR_CALLED); OBJ_RELEASE(Z_OBJ(call->This)); } - } else if ((call->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) && - !(call->func->common.fn_flags & ZEND_ACC_TRAMPOLINE_PERMANENT)) { - zend_do_release_trampoline = true; } if (ZEND_CALL_INFO(call) & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS) { @@ -3557,8 +3553,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_PARTIAL_SPEC_HANDLER( OBJ_RELEASE(ZEND_CLOSURE_OBJECT(call->func)); } - if (zend_do_release_trampoline) { - zend_free_trampoline(call->func); + if ((call->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) && + !(call->func->common.fn_flags & ZEND_ACC_TRAMPOLINE_PERMANENT)) { + zend_free_trampoline(call->func); } EX(call) = call->prev_execute_data; From 667d3d6a47b4a89f529e10283f6f5fd30512bdfc Mon Sep 17 00:00:00 2001 From: Joe Watkins Date: Thu, 17 Jun 2021 15:56:24 +0200 Subject: [PATCH 14/35] drop dup check --- Zend/zend_partial.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/Zend/zend_partial.c b/Zend/zend_partial.c index 27fc12dab2dd5..c04d85ba585bc 100644 --- a/Zend/zend_partial.c +++ b/Zend/zend_partial.c @@ -341,23 +341,21 @@ static HashTable *zend_partial_get_gc(zend_object *obj, zval **table, int *n) { zend_partial *partial = (zend_partial *)obj; - if (!partial->argc) { - *table = Z_TYPE(partial->This) == IS_OBJECT ? &partial->This : NULL; - *n = Z_TYPE(partial->This) == IS_OBJECT ? 1 : 0; + if (!partial->argc) { + *table = Z_TYPE(partial->This) == IS_OBJECT ? &partial->This : NULL; + *n = Z_TYPE(partial->This) == IS_OBJECT ? 1 : 0; } else { - zend_get_gc_buffer *buffer = zend_get_gc_buffer_create(); - - if (Z_TYPE(partial->This) == IS_OBJECT) { - zend_get_gc_buffer_add_zval(buffer, &partial->This); - } - - for (uint32_t arg = 0; arg < partial->argc; arg++) { - if (Z_OPT_REFCOUNTED(partial->argv[arg])) { - zend_get_gc_buffer_add_zval(buffer, &partial->argv[arg]); - } - } - - zend_get_gc_buffer_use(buffer, table, n); + zend_get_gc_buffer *buffer = zend_get_gc_buffer_create(); + + if (Z_TYPE(partial->This) == IS_OBJECT) { + zend_get_gc_buffer_add_zval(buffer, &partial->This); + } + + for (uint32_t arg = 0; arg < partial->argc; arg++) { + zend_get_gc_buffer_add_zval(buffer, &partial->argv[arg]); + } + + zend_get_gc_buffer_use(buffer, table, n); } return NULL; From 3fd01b654d20fa318015a3f1058ae54b33e2c6cf Mon Sep 17 00:00:00 2001 From: Joe Watkins Date: Thu, 17 Jun 2021 16:02:40 +0200 Subject: [PATCH 15/35] fix ubsan --- Zend/zend_partial.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Zend/zend_partial.c b/Zend/zend_partial.c index c04d85ba585bc..6fa8bd9bf73b2 100644 --- a/Zend/zend_partial.c +++ b/Zend/zend_partial.c @@ -763,7 +763,8 @@ ZEND_NAMED_FUNCTION(zend_partial_call_magic) fci.params = ecalloc(sizeof(zval), partial->argc + num_params); fci.param_count = zend_partial_apply( partial->argv, partial->argv + partial->argc, - params, params + num_params, fci.params, true); + params ? params : NULL, + params ? params + num_params : NULL, fci.params, true); if (fci.param_count < partial->func.common.required_num_args) { /* doesn't satisfy implementation */ From 90fcab603f28ed8dc2df12bc9ac263ebb1ebd774 Mon Sep 17 00:00:00 2001 From: Joe Watkins Date: Thu, 17 Jun 2021 16:57:57 +0200 Subject: [PATCH 16/35] Update Zend/zend_language_parser.y Co-authored-by: Nikita Popov --- Zend/zend_language_parser.y | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 5d0cd95313024..73fdd14ce451a 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -840,10 +840,8 @@ argument: expr { $$ = $1; } | identifier ':' expr { $$ = zend_ast_create(ZEND_AST_NAMED_ARG, $1, $3); } - | '?' { $$ = zend_ast_create(ZEND_AST_PLACEHOLDER_ARG); - $$->attr = _IS_PLACEHOLDER_ARG; } - | T_ELLIPSIS { $$ = zend_ast_create(ZEND_AST_PLACEHOLDER_ARG); - $$->attr = _IS_PLACEHOLDER_VARIADIC; } + | '?' { $$ = zend_ast_create_ex(ZEND_AST_PLACEHOLDER_ARG, _IS_PLACEHOLDER_ARG); } + | T_ELLIPSIS { $$ = zend_ast_create_ex(ZEND_AST_PLACEHOLDER_ARG, _IS_PLACEHOLDER_VARIADIC); } | T_ELLIPSIS expr { $$ = zend_ast_create(ZEND_AST_UNPACK, $2); } ; From 0fafba31e82ee5bf2e3f86bb7502fbf38695904a Mon Sep 17 00:00:00 2001 From: Joe Watkins Date: Thu, 17 Jun 2021 16:58:05 +0200 Subject: [PATCH 17/35] Update Zend/zend_compile.c Co-authored-by: Nikita Popov --- Zend/zend_compile.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 8d8957fdbaeaa..428c2da64c50e 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -3516,7 +3516,7 @@ uint32_t zend_compile_args( "Variadic placeholder may only appear once"); } - uses_variadic_placeholder = 1; + uses_variadic_placeholder = true; } else if (arg->attr == _IS_PLACEHOLDER_ARG) { if (uses_named_args) { zend_error_noreturn(E_COMPILE_ERROR, From bdf2108cda97234d9a745f83cad032c5d2fb436e Mon Sep 17 00:00:00 2001 From: Joe Watkins Date: Thu, 17 Jun 2021 17:01:29 +0200 Subject: [PATCH 18/35] drop dup check for permanent trampoline --- Zend/zend_vm_def.h | 3 +-- Zend/zend_vm_execute.h | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 53132025e238d..1e0302d343d3a 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -8833,8 +8833,7 @@ ZEND_VM_HANDLER(203, ZEND_DO_FCALL_PARTIAL, ANY, ANY) OBJ_RELEASE(ZEND_CLOSURE_OBJECT(call->func)); } - if ((call->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) && - !(call->func->common.fn_flags & ZEND_ACC_TRAMPOLINE_PERMANENT)) { + if ((call->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) { zend_free_trampoline(call->func); } diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index c239ddd53f1a6..afb9627abc158 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -3553,8 +3553,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_PARTIAL_SPEC_HANDLER( OBJ_RELEASE(ZEND_CLOSURE_OBJECT(call->func)); } - if ((call->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) && - !(call->func->common.fn_flags & ZEND_ACC_TRAMPOLINE_PERMANENT)) { + if ((call->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) { zend_free_trampoline(call->func); } From 89a533021d6f03a8d608a6828ed1fc89696991e2 Mon Sep 17 00:00:00 2001 From: Joe Watkins Date: Thu, 17 Jun 2021 17:03:55 +0200 Subject: [PATCH 19/35] fix flags --- Zend/zend_compile.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 902dd766b36e4..29a99c090cd84 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -301,7 +301,7 @@ typedef struct _zend_oparray_context { /* loaded from file cache to process memory | | | */ #define ZEND_ACC_FILE_CACHED (1 << 27) /* X | | | */ /* | | | */ -/* Function Flags (unused: 27-30) | | | */ +/* Function Flags (unused: 29-30) | | | */ /* ============== | | | */ /* | | | */ /* deprecation flag | | | */ @@ -361,7 +361,7 @@ typedef struct _zend_oparray_context { #define ZEND_ACC_PARTIAL (1 << 27) /* | X | | */ /* | | | */ /* trampoline is permanent | | | */ -#define ZEND_ACC_TRAMPOLINE_PERMANENT (1 << 29) /* | X | | */ +#define ZEND_ACC_TRAMPOLINE_PERMANENT (1 << 28) /* | X | | */ /* | | | */ /* op_array uses strict mode types | | | */ #define ZEND_ACC_STRICT_TYPES (1U << 31) /* | X | | */ From ead14d33f1d1f8a2a6f74c2e1c3668dbe6e8f770 Mon Sep 17 00:00:00 2001 From: Joe Watkins Date: Thu, 17 Jun 2021 17:18:33 +0200 Subject: [PATCH 20/35] fixing things --- Zend/zend_partial.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Zend/zend_partial.c b/Zend/zend_partial.c index 6fa8bd9bf73b2..ba03d1d2553ba 100644 --- a/Zend/zend_partial.c +++ b/Zend/zend_partial.c @@ -442,7 +442,7 @@ void zend_partial_startup(void) { memset(&zend_call_magic_arginfo, 0, sizeof(zend_arg_info) * 1); - zend_call_magic_arginfo[0].name = zend_string_init_interned("args", sizeof("args")-1, 1); + zend_call_magic_arginfo[0].name = ZSTR_KNOWN(ZEND_STR_ARGS); zend_call_magic_arginfo[0].type = (zend_type) ZEND_TYPE_INIT_NONE(_ZEND_IS_VARIADIC_BIT); } @@ -477,9 +477,9 @@ static zend_always_inline zend_string* zend_partial_symbol_name(zend_execute_dat *symbol; if (scope) { - symbol = zend_strpprintf(0, "%s::%s", ZSTR_VAL(scope), ZSTR_VAL(name)); + symbol = zend_create_member_string(scope, name); } else { - symbol = zend_strpprintf(0, "%s", ZSTR_VAL(name)); + symbol = zend_string_copy(name); } zend_string_release(name); From b9aa841611e239d85f52010d5c1e3ab8402536bf Mon Sep 17 00:00:00 2001 From: Joe Watkins Date: Thu, 17 Jun 2021 17:13:56 +0200 Subject: [PATCH 21/35] Update Zend/zend_partial.c Co-authored-by: Nikita Popov --- Zend/zend_partial.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Zend/zend_partial.c b/Zend/zend_partial.c index ba03d1d2553ba..fc6b2b6056197 100644 --- a/Zend/zend_partial.c +++ b/Zend/zend_partial.c @@ -518,7 +518,7 @@ static zend_always_inline void zend_partial_prototype_overflow(zend_function *fu static zend_always_inline void zend_partial_args_underflow(zend_function *function, zend_string *symbol, uint32_t args, uint32_t expected, bool calling, bool prototype) { const char *what = calling ? - "arguments" : "arguments and or placeholders"; + "arguments" : "arguments or placeholders"; const char *from = prototype ? "application" : "implementation"; const char *limit = function->common.num_args <= function->common.required_num_args ? From a1d76e69bf359888b219be05d1098ebd2dfb762b Mon Sep 17 00:00:00 2001 From: Joe Watkins Date: Thu, 17 Jun 2021 18:22:36 +0200 Subject: [PATCH 22/35] fix tests, fix count --- Zend/tests/partial_application/errors_001.phpt | 8 ++++---- Zend/tests/partial_application/variation_pass_001.phpt | 2 +- .../partial_application/variation_variadics_003.phpt | 2 +- Zend/zend_partial.c | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Zend/tests/partial_application/errors_001.phpt b/Zend/tests/partial_application/errors_001.phpt index 705d5af4cde66..d6e37051c1eca 100644 --- a/Zend/tests/partial_application/errors_001.phpt +++ b/Zend/tests/partial_application/errors_001.phpt @@ -31,8 +31,8 @@ try { } ?> --EXPECTF-- -not enough arguments and or placeholders for application of foo, 1 given and exactly 3 expected, declared in %s on line 2 -too many arguments and or placeholders for application of foo, 4 given and a maximum of 3 expected, declared in %s on line 2 -not enough arguments and or placeholders for application of property_exists, 1 given and exactly 2 expected -too many arguments and or placeholders for application of usleep, 2 given and a maximum of 1 expected +not enough arguments or placeholders for application of foo, 1 given and exactly 3 expected, declared in %s on line 2 +too many arguments or placeholders for application of foo, 4 given and a maximum of 3 expected, declared in %s on line 2 +not enough arguments or placeholders for application of property_exists, 1 given and exactly 2 expected +too many arguments or placeholders for application of usleep, 2 given and a maximum of 1 expected diff --git a/Zend/tests/partial_application/variation_pass_001.phpt b/Zend/tests/partial_application/variation_pass_001.phpt index c31d0fcb2470d..e432e079b45dd 100644 --- a/Zend/tests/partial_application/variation_pass_001.phpt +++ b/Zend/tests/partial_application/variation_pass_001.phpt @@ -11,4 +11,4 @@ try { } ?> --EXPECT-- -too many arguments and or placeholders for application of Foo::__construct, 1 given and a maximum of 0 expected +too many arguments or placeholders for application of Foo::__construct, 1 given and a maximum of 0 expected diff --git a/Zend/tests/partial_application/variation_variadics_003.phpt b/Zend/tests/partial_application/variation_variadics_003.phpt index 0631f7beb5e76..c5e41ab1aeb50 100644 --- a/Zend/tests/partial_application/variation_variadics_003.phpt +++ b/Zend/tests/partial_application/variation_variadics_003.phpt @@ -38,7 +38,7 @@ $foo(1, 2, 3); // OK ?> --EXPECTF-- too many arguments for application of foo, 3 given and a maximum of 2 expected, declared in %s on line %d -too many arguments and or placeholders for application of foo, 3 given and a maximum of 2 expected, declared in %s on line %d +too many arguments or placeholders for application of foo, 3 given and a maximum of 2 expected, declared in %s on line %d too many arguments for application of bar, 3 given and a maximum of 2 expected, declared in %s on line %d array(3) { [0]=> diff --git a/Zend/zend_partial.c b/Zend/zend_partial.c index fc6b2b6056197..3290709078623 100644 --- a/Zend/zend_partial.c +++ b/Zend/zend_partial.c @@ -67,7 +67,7 @@ static zend_arg_info zend_call_magic_arginfo[1]; (ZEND_CALL_INFO(partial) & flag) static zend_always_inline uint32_t zend_partial_signature_size(zend_partial *partial) { - uint32_t count = partial->func.common.num_args + partial->argc; + uint32_t count = MAX(partial->func.common.num_args, partial->argc); if (ZEND_PARTIAL_FUNC_FLAG(&partial->func, ZEND_ACC_HAS_RETURN_TYPE)) { count++; @@ -539,7 +539,7 @@ static zend_always_inline void zend_partial_args_underflow(zend_function *functi static zend_always_inline void zend_partial_args_overflow(zend_function *function, zend_string *symbol, uint32_t args, uint32_t expected, bool calling, bool prototype) { const char *what = calling ? - "arguments" : "arguments and or placeholders"; + "arguments" : "arguments or placeholders"; const char *from = prototype ? "application" : "implementation"; From 88aa29c668293b0b2ae804716ffc3e6e641b0aaf Mon Sep 17 00:00:00 2001 From: Joe Watkins Date: Thu, 17 Jun 2021 18:25:59 +0200 Subject: [PATCH 23/35] comments --- Zend/zend_partial.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Zend/zend_partial.c b/Zend/zend_partial.c index 3290709078623..26c3663d3189f 100644 --- a/Zend/zend_partial.c +++ b/Zend/zend_partial.c @@ -23,9 +23,13 @@ typedef struct _zend_partial { zend_object std; + /* this is the prototype generated from application */ zend_function prototype; zval This; + /* this is the unmodified function that will be invoked at call time */ zend_function func; + /* this will be returned by get_closure, and has arginfo of prototype + and will invoke func */ zend_function trampoline; uint32_t argc; zval *argv; From 81b64fff294cc986e831ad9dd88a58d4f9d2eb17 Mon Sep 17 00:00:00 2001 From: Joe Watkins Date: Thu, 17 Jun 2021 18:26:43 +0200 Subject: [PATCH 24/35] drop silly macro --- Zend/zend_partial.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Zend/zend_partial.c b/Zend/zend_partial.c index 26c3663d3189f..d519cfe844419 100644 --- a/Zend/zend_partial.c +++ b/Zend/zend_partial.c @@ -85,10 +85,8 @@ static zend_always_inline uint32_t zend_partial_signature_size(zend_partial *par return count * sizeof(zend_arg_info); } -#define ZEND_PARTIAL_SIGNATURE_SIZE(partial) zend_partial_signature_size(partial) - static zend_always_inline zend_function* zend_partial_signature_create(zend_partial *partial, zend_function *prototype) { - zend_arg_info *signature = emalloc(ZEND_PARTIAL_SIGNATURE_SIZE(partial)), *info = signature; + zend_arg_info *signature = emalloc(zend_partial_signature_size(partial)), *info = signature; memcpy(&partial->prototype, prototype, ZEND_PARTIAL_FUNC_SIZE(prototype)); From 67c3b669ef2c9d0f71dd37ea8f4312ac9a5a5061 Mon Sep 17 00:00:00 2001 From: Joe Watkins Date: Fri, 18 Jun 2021 16:33:35 +0200 Subject: [PATCH 25/35] fix another gc issue --- .../partial_application/variation_gc_003.phpt | 15 +++++++++++++++ Zend/zend_partial.c | 14 +++++++++++--- 2 files changed, 26 insertions(+), 3 deletions(-) create mode 100644 Zend/tests/partial_application/variation_gc_003.phpt diff --git a/Zend/tests/partial_application/variation_gc_003.phpt b/Zend/tests/partial_application/variation_gc_003.phpt new file mode 100644 index 0000000000000..c919d488eac14 --- /dev/null +++ b/Zend/tests/partial_application/variation_gc_003.phpt @@ -0,0 +1,15 @@ +--TEST-- +Partial application variation GC +--FILE-- +prop = test(?, x: $obj); + +echo "OK"; +?> +--EXPECT-- +OK diff --git a/Zend/zend_partial.c b/Zend/zend_partial.c index d519cfe844419..7a12a0a8b7854 100644 --- a/Zend/zend_partial.c +++ b/Zend/zend_partial.c @@ -343,10 +343,10 @@ static HashTable *zend_partial_get_gc(zend_object *obj, zval **table, int *n) { zend_partial *partial = (zend_partial *)obj; - if (!partial->argc) { + if (!partial->argc && !partial->named) { *table = Z_TYPE(partial->This) == IS_OBJECT ? &partial->This : NULL; *n = Z_TYPE(partial->This) == IS_OBJECT ? 1 : 0; - } else { + } else { zend_get_gc_buffer *buffer = zend_get_gc_buffer_create(); if (Z_TYPE(partial->This) == IS_OBJECT) { @@ -357,8 +357,16 @@ static HashTable *zend_partial_get_gc(zend_object *obj, zval **table, int *n) zend_get_gc_buffer_add_zval(buffer, &partial->argv[arg]); } + if (partial->named) { + zval named; + + ZVAL_ARR(&named, partial->named); + + zend_get_gc_buffer_add_zval(buffer, &named); + } + zend_get_gc_buffer_use(buffer, table, n); - } + } return NULL; } From 3f8a12aafc103ed368dbde9e228f800e9ac82452 Mon Sep 17 00:00:00 2001 From: Joe Watkins Date: Fri, 18 Jun 2021 17:07:24 +0200 Subject: [PATCH 26/35] fix uaf in unfinished calls, fix leak args --- .../partial_application/variation_ex_001.phpt | 14 ++++++++++++++ .../partial_application/variation_nocall_001.phpt | 12 ++++++++++++ Zend/zend_execute.c | 13 ++++++++----- Zend/zend_vm_def.h | 2 ++ Zend/zend_vm_execute.h | 2 ++ 5 files changed, 38 insertions(+), 5 deletions(-) create mode 100644 Zend/tests/partial_application/variation_ex_001.phpt create mode 100644 Zend/tests/partial_application/variation_nocall_001.phpt diff --git a/Zend/tests/partial_application/variation_ex_001.phpt b/Zend/tests/partial_application/variation_ex_001.phpt new file mode 100644 index 0000000000000..dc72ccdae797c --- /dev/null +++ b/Zend/tests/partial_application/variation_ex_001.phpt @@ -0,0 +1,14 @@ +--TEST-- +Partial application variation uaf in cleanup unfinished calls +--FILE-- + +--EXPECT-- +OK diff --git a/Zend/tests/partial_application/variation_nocall_001.phpt b/Zend/tests/partial_application/variation_nocall_001.phpt new file mode 100644 index 0000000000000..1f570bad2cfa5 --- /dev/null +++ b/Zend/tests/partial_application/variation_nocall_001.phpt @@ -0,0 +1,12 @@ +--TEST-- +Partial application variation no call args leak +--FILE-- + +--EXPECT-- +OK diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index b6ad8e736d103..96814d4320256 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -1159,7 +1159,7 @@ static zend_never_inline ZEND_ATTRIBUTE_UNUSED bool zend_verify_internal_arg_typ static zend_always_inline bool zend_internal_call_should_throw(zend_function *fbc, zend_execute_data *call) { if (fbc->internal_function.handler == ZEND_FN(pass) || - fbc->internal_function.handler == zend_partial_call_magic) { + fbc->internal_function.handler == zend_partial_call_magic) { /* Be lenient about the special pass functions. */ return 0; } @@ -3835,6 +3835,7 @@ static void cleanup_unfinished_calls(zend_execute_data *execute_data, uint32_t o case ZEND_DO_ICALL: case ZEND_DO_UCALL: case ZEND_DO_FCALL_BY_NAME: + case ZEND_DO_FCALL_PARTIAL: level++; break; case ZEND_INIT_FCALL: @@ -3871,6 +3872,7 @@ static void cleanup_unfinished_calls(zend_execute_data *execute_data, uint32_t o case ZEND_SEND_ARRAY: case ZEND_SEND_UNPACK: case ZEND_CHECK_UNDEF_ARGS: + case ZEND_CHECK_PARTIAL_ARGS: if (level == 0) { do_exit = 1; } @@ -3890,6 +3892,7 @@ static void cleanup_unfinished_calls(zend_execute_data *execute_data, uint32_t o case ZEND_DO_ICALL: case ZEND_DO_UCALL: case ZEND_DO_FCALL_BY_NAME: + case ZEND_DO_FCALL_PARTIAL: level++; break; case ZEND_INIT_FCALL: @@ -3912,9 +3915,6 @@ static void cleanup_unfinished_calls(zend_execute_data *execute_data, uint32_t o zend_vm_stack_free_args(EX(call)); - if (ZEND_CALL_INFO(call) & ZEND_CALL_RELEASE_THIS) { - OBJ_RELEASE(Z_OBJ(call->This)); - } if (ZEND_CALL_INFO(call) & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS) { zend_free_extra_named_params(call->extra_named_params); } @@ -3924,6 +3924,9 @@ static void cleanup_unfinished_calls(zend_execute_data *execute_data, uint32_t o zend_string_release_ex(call->func->common.function_name, 0); zend_free_trampoline(call->func); } + if (ZEND_CALL_INFO(call) & ZEND_CALL_RELEASE_THIS) { + OBJ_RELEASE(Z_OBJ(call->This)); + } EX(call) = call->prev_execute_data; zend_vm_stack_free_call_frame(call); @@ -4511,7 +4514,7 @@ zval * ZEND_FASTCALL zend_handle_named_arg( arg = ZEND_CALL_VAR_NUM(call, arg_offset); if (UNEXPECTED(Z_TYPE_P(arg) == _IS_PLACEHOLDER_VARIADIC)) { - ZVAL_UNDEF(arg); + ZVAL_UNDEF(arg); } if (UNEXPECTED(!Z_ISUNDEF_P(arg))) { diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 1e0302d343d3a..35c95f59cbc54 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -8821,6 +8821,8 @@ ZEND_VM_HANDLER(203, ZEND_DO_FCALL_PARTIAL, ANY, ANY) GC_ADD_FLAGS(Z_OBJ(call->This), IS_OBJ_DESTRUCTOR_CALLED); OBJ_RELEASE(Z_OBJ(call->This)); } + } else { + zend_vm_stack_free_args(call); } if (ZEND_CALL_INFO(call) & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS) { diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index afb9627abc158..fa284812bba3c 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -3541,6 +3541,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_PARTIAL_SPEC_HANDLER( GC_ADD_FLAGS(Z_OBJ(call->This), IS_OBJ_DESTRUCTOR_CALLED); OBJ_RELEASE(Z_OBJ(call->This)); } + } else { + zend_vm_stack_free_args(call); } if (ZEND_CALL_INFO(call) & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS) { From bde700f76b09101f69966637a04ec348050278c7 Mon Sep 17 00:00:00 2001 From: Joe Watkins Date: Fri, 18 Jun 2021 17:18:35 +0200 Subject: [PATCH 27/35] put assert back --- Zend/zend_partial.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Zend/zend_partial.c b/Zend/zend_partial.c index 7a12a0a8b7854..1b0c659d0e622 100644 --- a/Zend/zend_partial.c +++ b/Zend/zend_partial.c @@ -126,7 +126,7 @@ static zend_always_inline zend_function* zend_partial_signature_create(zend_part ZEND_TYPE_FULL_MASK(info->type) &= ~_ZEND_IS_VARIADIC_BIT; info++; } else { - break; + ZEND_ASSERT(0); } } else if (Z_IS_PLACEHOLDER_VARIADIC_P(arg) || Z_ISUNDEF_P(arg)) { if (offset < partial->func.common.num_args) { From b699d656e3f39d35e3ed75ab2531b7b5bc25f3ca Mon Sep 17 00:00:00 2001 From: Joe Watkins Date: Fri, 18 Jun 2021 17:20:16 +0200 Subject: [PATCH 28/35] fix indent, repeat type --- Zend/zend_partial.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Zend/zend_partial.c b/Zend/zend_partial.c index 1b0c659d0e622..2d63e8b108c3e 100644 --- a/Zend/zend_partial.c +++ b/Zend/zend_partial.c @@ -273,10 +273,11 @@ static zend_always_inline void zend_partial_debug_add(zend_function *function, H } static zend_always_inline void zend_partial_debug_fill(zend_partial *partial, HashTable *ht) { - zval *arg = partial->argv, - *aend = arg + partial->argc; - zend_arg_info *info = partial->func.common.arg_info, - *iend = info + partial->func.common.num_args; + zval *arg = partial->argv; + zval *aend = arg + partial->argc; + + zend_arg_info *info = partial->func.common.arg_info; + zend_arg_info *iend = info + partial->func.common.num_args; while (info < iend) { zval param; From 0e8a0a0467772b912122f00606e1dbdb96409de8 Mon Sep 17 00:00:00 2001 From: Joe Watkins Date: Fri, 18 Jun 2021 17:22:27 +0200 Subject: [PATCH 29/35] use hash add variants --- Zend/zend_partial.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/Zend/zend_partial.c b/Zend/zend_partial.c index 2d63e8b108c3e..de187903b5074 100644 --- a/Zend/zend_partial.c +++ b/Zend/zend_partial.c @@ -264,11 +264,11 @@ static zend_always_inline zend_object* zend_partial_new(zend_class_entry *type, static zend_always_inline void zend_partial_debug_add(zend_function *function, HashTable *ht, zend_arg_info *info, zval *value) { if (function->type == ZEND_USER_FUNCTION || ZEND_PARTIAL_FUNC_FLAG(function, ZEND_ACC_USER_ARG_INFO)) { - zend_hash_add(ht, info->name, value); + zend_hash_add_new(ht, info->name, value); } else { zend_internal_arg_info *internal = (zend_internal_arg_info*) info; - zend_hash_str_add(ht, internal->name, strlen(internal->name), value); + zend_hash_str_add_new(ht, internal->name, strlen(internal->name), value); } } @@ -286,17 +286,13 @@ static zend_always_inline void zend_partial_debug_fill(zend_partial *partial, Ha if (arg < aend) { if (Z_IS_NOT_PLACEHOLDER_P(arg)) { - ZVAL_COPY_VALUE(¶m, arg); + ZVAL_COPY(¶m, arg); } - arg++; } zend_partial_debug_add(&partial->func, ht, info, ¶m); - if (Z_OPT_REFCOUNTED(param)) { - Z_ADDREF(param); - } info++; } @@ -311,11 +307,8 @@ static zend_always_inline void zend_partial_debug_fill(zend_partial *partial, Ha if (Z_IS_NOT_PLACEHOLDER_P(arg)) { zend_hash_next_index_insert(Z_ARRVAL(variadics), arg); - if (Z_OPT_REFCOUNTED_P(arg)) { - Z_ADDREF_P(arg); - } + Z_TRY_ADDREF_P(arg); } - arg++; } From 711b33a6d6f085de0068f8e6a40302beafa6f6c1 Mon Sep 17 00:00:00 2001 From: Joe Watkins Date: Fri, 18 Jun 2021 17:29:22 +0200 Subject: [PATCH 30/35] insert null in debug info --- .../partial_application/variation_debug_002.phpt | 4 +++- .../partial_application/variation_parent_001.phpt | 4 +++- Zend/zend_partial.c | 12 ++++++++---- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/Zend/tests/partial_application/variation_debug_002.phpt b/Zend/tests/partial_application/variation_debug_002.phpt index ed40f8222911f..ef6fa8e545336 100644 --- a/Zend/tests/partial_application/variation_debug_002.phpt +++ b/Zend/tests/partial_application/variation_debug_002.phpt @@ -27,7 +27,7 @@ object(Closure)#%d (2) { int(3) } ["arrays"]=> - array(2) { + array(3) { [0]=> array(3) { [0]=> @@ -37,6 +37,8 @@ object(Closure)#%d (2) { [2]=> int(6) } + [1]=> + NULL ["four"]=> object(stdClass)#%d (0) { } diff --git a/Zend/tests/partial_application/variation_parent_001.phpt b/Zend/tests/partial_application/variation_parent_001.phpt index efb77fff1f71b..c6440a9481beb 100644 --- a/Zend/tests/partial_application/variation_parent_001.phpt +++ b/Zend/tests/partial_application/variation_parent_001.phpt @@ -33,7 +33,9 @@ object(Closure)#%d (3) { ["b"]=> int(20) ["c"]=> - array(0) { + array(1) { + [0]=> + NULL } } } diff --git a/Zend/zend_partial.c b/Zend/zend_partial.c index de187903b5074..2b5810975a3e6 100644 --- a/Zend/zend_partial.c +++ b/Zend/zend_partial.c @@ -304,11 +304,15 @@ static zend_always_inline void zend_partial_debug_fill(zend_partial *partial, Ha zend_partial_debug_add(&partial->func, ht, info, &variadics); while (arg < aend) { - if (Z_IS_NOT_PLACEHOLDER_P(arg)) { - zend_hash_next_index_insert(Z_ARRVAL(variadics), arg); + zval param; + + ZVAL_NULL(¶m); - Z_TRY_ADDREF_P(arg); + if (Z_IS_NOT_PLACEHOLDER_P(arg)) { + ZVAL_COPY(¶m, arg); } + + zend_hash_next_index_insert(Z_ARRVAL(variadics), ¶m); arg++; } @@ -565,7 +569,7 @@ void zend_partial_args_check(zend_execute_data *call) { zend_function *function = call->func; uint32_t num = ZEND_CALL_NUM_ARGS(call) + - (ZEND_PARTIAL_CALL_FLAG(call, ZEND_CALL_VARIADIC_PLACEHOLDER) ? -1 : 0); + (ZEND_PARTIAL_CALL_FLAG(call, ZEND_CALL_VARIADIC_PLACEHOLDER) ? -1 : 0); if (num < function->common.required_num_args) { /* this check is delayed in the case of variadic application */ From 9400a6930e5edbaba7052c2e9a0203816637de96 Mon Sep 17 00:00:00 2001 From: Joe Watkins Date: Fri, 18 Jun 2021 17:32:17 +0200 Subject: [PATCH 31/35] drop sprintf for zend_string_init --- Zend/zend_partial.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Zend/zend_partial.c b/Zend/zend_partial.c index 2b5810975a3e6..07131a0d4170a 100644 --- a/Zend/zend_partial.c +++ b/Zend/zend_partial.c @@ -457,7 +457,7 @@ void zend_partial_startup(void) { static zend_always_inline zend_string* zend_partial_function_name(zend_function *function) { if (function->type == ZEND_INTERNAL_FUNCTION) { if (function->internal_function.handler == zend_pass_function.handler) { - return zend_strpprintf(0, "__construct"); + return zend_string_init("__construct", sizeof("__construct")-1, 0); } } return zend_string_copy(function->common.function_name); From 583264d25ab893f1232a71f609ae04ddcbe0afee Mon Sep 17 00:00:00 2001 From: Joe Watkins Date: Fri, 18 Jun 2021 17:39:13 +0200 Subject: [PATCH 32/35] fix uaf, order of destruction --- .../partial_application/variation_nocall_002.phpt | 14 ++++++++++++++ Zend/zend_vm_def.h | 8 ++++---- Zend/zend_vm_execute.h | 8 ++++---- 3 files changed, 22 insertions(+), 8 deletions(-) create mode 100644 Zend/tests/partial_application/variation_nocall_002.phpt diff --git a/Zend/tests/partial_application/variation_nocall_002.phpt b/Zend/tests/partial_application/variation_nocall_002.phpt new file mode 100644 index 0000000000000..35bcddc15e2a3 --- /dev/null +++ b/Zend/tests/partial_application/variation_nocall_002.phpt @@ -0,0 +1,14 @@ +--TEST-- +Partial application variation no call order of destruction +--FILE-- +method(...)(...); + +echo "OK"; +?> +--EXPECT-- +OK diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 35c95f59cbc54..1e92f1c9e9b91 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -8829,16 +8829,16 @@ ZEND_VM_HANDLER(203, ZEND_DO_FCALL_PARTIAL, ANY, ANY) zend_array_release(call->extra_named_params); } + if ((call->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) { + zend_free_trampoline(call->func); + } + if (ZEND_CALL_INFO(call) & ZEND_CALL_RELEASE_THIS) { OBJ_RELEASE(Z_OBJ(call->This)); } else if (ZEND_CALL_INFO(call) & ZEND_CALL_CLOSURE) { OBJ_RELEASE(ZEND_CLOSURE_OBJECT(call->func)); } - if ((call->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) { - zend_free_trampoline(call->func); - } - EX(call) = call->prev_execute_data; zend_vm_stack_free_call_frame(call); diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index fa284812bba3c..ed3daffc7c5cb 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -3549,16 +3549,16 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_PARTIAL_SPEC_HANDLER( zend_array_release(call->extra_named_params); } + if ((call->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) { + zend_free_trampoline(call->func); + } + if (ZEND_CALL_INFO(call) & ZEND_CALL_RELEASE_THIS) { OBJ_RELEASE(Z_OBJ(call->This)); } else if (ZEND_CALL_INFO(call) & ZEND_CALL_CLOSURE) { OBJ_RELEASE(ZEND_CLOSURE_OBJECT(call->func)); } - if ((call->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) { - zend_free_trampoline(call->func); - } - EX(call) = call->prev_execute_data; zend_vm_stack_free_call_frame(call); From 6afa0d104ec0a6d46b5fc6a96521336306c3cd1f Mon Sep 17 00:00:00 2001 From: Joe Watkins Date: Fri, 18 Jun 2021 17:41:57 +0200 Subject: [PATCH 33/35] set ce ptr --- Zend/zend_partial.c | 1 + 1 file changed, 1 insertion(+) diff --git a/Zend/zend_partial.c b/Zend/zend_partial.c index 07131a0d4170a..b6b1a057f0971 100644 --- a/Zend/zend_partial.c +++ b/Zend/zend_partial.c @@ -387,6 +387,7 @@ static int zend_partial_get_closure(zend_object *obj, zend_class_entry **ce_ptr, *fptr_ptr = &partial->trampoline; *obj_ptr = (zend_object*) &partial->std; + *ce_ptr = Z_TYPE(partial->This) == IS_OBJECT ? Z_OBJCE(partial->This) : NULL; return SUCCESS; } From 12d600635743540754d74a53fadac6d1cc2788a9 Mon Sep 17 00:00:00 2001 From: Joe Watkins Date: Fri, 18 Jun 2021 17:53:13 +0200 Subject: [PATCH 34/35] fix null ptr deref --- Zend/tests/partial_application/magic_005.phpt | 33 +++++++++++++++++++ Zend/zend_object_handlers.c | 12 +++++-- 2 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 Zend/tests/partial_application/magic_005.phpt diff --git a/Zend/tests/partial_application/magic_005.phpt b/Zend/tests/partial_application/magic_005.phpt new file mode 100644 index 0000000000000..ab66f9448e2c1 --- /dev/null +++ b/Zend/tests/partial_application/magic_005.phpt @@ -0,0 +1,33 @@ +--TEST-- +Partial application magic null ptr deref in arginfo +--FILE-- +method(?); +var_dump($bar); +?> +--EXPECTF-- +object(Closure)#%d (3) { + ["this"]=> + object(Foo)#%d (0) { + } + ["parameter"]=> + array(1) { + ["$args"]=> + string(10) "" + } + ["args"]=> + array(1) { + ["args"]=> + array(1) { + [0]=> + NULL + } + } +} + diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index fdbab21a9bec7..dee5557343d54 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -35,6 +35,8 @@ #define ZEND_WRONG_PROPERTY_OFFSET 0 +static zend_arg_info zend_call_trampoline_arginfo[1] = {{0}}; + /* guard flags */ #define IN_GET (1<<0) #define IN_SET (1<<1) @@ -1125,6 +1127,13 @@ ZEND_API int zend_check_protected(zend_class_entry *ce, zend_class_entry *scope) } /* }}} */ +static zend_always_inline zend_arg_info* zend_get_call_trampoline_arginfo() { + if (UNEXPECTED(zend_call_trampoline_arginfo[0].name == NULL)) { + zend_call_trampoline_arginfo[0].name = ZSTR_KNOWN(ZEND_STR_ARGS); + } + return zend_call_trampoline_arginfo; +} + ZEND_API zend_function *zend_get_call_trampoline_func(zend_class_entry *ce, zend_string *method_name, int is_static) /* {{{ */ { size_t mname_len; @@ -1134,7 +1143,6 @@ ZEND_API zend_function *zend_get_call_trampoline_func(zend_class_entry *ce, zend * The low bit must be zero, to not be interpreted as a MAP_PTR offset. */ static const void *dummy = (void*)(intptr_t)2; - static const zend_arg_info arg_info[1] = {{0}}; ZEND_ASSERT(fbc); @@ -1172,7 +1180,7 @@ ZEND_API zend_function *zend_get_call_trampoline_func(zend_class_entry *ce, zend func->prototype = NULL; func->num_args = 0; func->required_num_args = 0; - func->arg_info = (zend_arg_info *) arg_info; + func->arg_info = zend_get_call_trampoline_arginfo(); return (zend_function*)func; } From fd6204789743054bc1fedae2ffeb193c0f66bb4f Mon Sep 17 00:00:00 2001 From: Joe Watkins Date: Fri, 18 Jun 2021 18:36:48 +0200 Subject: [PATCH 35/35] fix wrong signature check --- .../variation_variadics_008.phpt | 17 +++++++++++++++++ Zend/zend_partial.c | 6 +++--- 2 files changed, 20 insertions(+), 3 deletions(-) create mode 100644 Zend/tests/partial_application/variation_variadics_008.phpt diff --git a/Zend/tests/partial_application/variation_variadics_008.phpt b/Zend/tests/partial_application/variation_variadics_008.phpt new file mode 100644 index 0000000000000..214ed9b4db9cb --- /dev/null +++ b/Zend/tests/partial_application/variation_variadics_008.phpt @@ -0,0 +1,17 @@ +--TEST-- +Partial application variation variadics wrong signature checked +--FILE-- +getMessage() . PHP_EOL; +} +?> +--EXPECT-- +too many arguments or placeholders for application of Closure::__invoke, 2 given and a maximum of 1 expected + diff --git a/Zend/zend_partial.c b/Zend/zend_partial.c index b6b1a057f0971..55da8c5f82f75 100644 --- a/Zend/zend_partial.c +++ b/Zend/zend_partial.c @@ -239,7 +239,7 @@ static zend_always_inline void zend_partial_trampoline_create(zend_partial *part trampoline->common = partial->prototype.common; trampoline->type = ZEND_INTERNAL_FUNCTION; trampoline->internal_function.fn_flags = - ZEND_ACC_PUBLIC | ZEND_ACC_CALL_VIA_HANDLER | ZEND_ACC_TRAMPOLINE_PERMANENT | (partial->func.common.fn_flags & keep_flags); + ZEND_ACC_PUBLIC | ZEND_ACC_CALL_VIA_HANDLER | ZEND_ACC_PARTIAL | ZEND_ACC_TRAMPOLINE_PERMANENT | (partial->prototype.common.fn_flags & keep_flags); if (partial->func.type != ZEND_INTERNAL_FUNCTION || (partial->func.common.fn_flags & ZEND_ACC_USER_ARG_INFO)) { trampoline->internal_function.fn_flags |= ZEND_ACC_USER_ARG_INFO; @@ -580,11 +580,11 @@ void zend_partial_args_check(zend_execute_data *call) { zend_string *symbol = zend_partial_symbol_name(call, function); zend_partial_args_underflow( - function, symbol, + function, symbol, num, function->common.required_num_args, false, true); zend_string_release(symbol); } else if (num > function->common.num_args && - !ZEND_PARTIAL_FUNC_FLAG(call->func, ZEND_ACC_VARIADIC)) { + !ZEND_PARTIAL_FUNC_FLAG(function, ZEND_ACC_VARIADIC)) { zend_string *symbol = zend_partial_symbol_name(call, function); zend_partial_args_overflow( function, symbol,