]> granicus.if.org Git - php/commitdiff
Fixed bug that jmp in try block jmp over finally block
authorXinchen Hui <laruence@php.net>
Wed, 22 Aug 2012 10:32:03 +0000 (18:32 +0800)
committerXinchen Hui <laruence@php.net>
Wed, 22 Aug 2012 10:32:03 +0000 (18:32 +0800)
Refactor the implemention,  make codes clear

23 files changed:
Zend/tests/catch_finally_001.phpt
Zend/tests/catch_finally_002.phpt
Zend/tests/catch_finally_003.phpt
Zend/tests/catch_finally_004.phpt
Zend/tests/catch_finally_005.phpt
Zend/tests/catch_finally_006.phpt
Zend/tests/try_catch_finally_005.phpt [new file with mode: 0644]
Zend/tests/try_catch_finally_006.phpt [new file with mode: 0644]
Zend/tests/try_catch_finally_007.phpt [new file with mode: 0644]
Zend/tests/try_finally_001.phpt
Zend/tests/try_finally_002.phpt
Zend/tests/try_finally_003.phpt
Zend/tests/try_finally_004.phpt
Zend/tests/try_finally_005.phpt
Zend/tests/try_finally_006.phpt
Zend/tests/try_finally_007.phpt
Zend/tests/try_finally_008.phpt
Zend/tests/try_finally_009.phpt
Zend/zend_compile.c
Zend/zend_compile.h
Zend/zend_opcode.c
Zend/zend_vm_def.h
Zend/zend_vm_execute.h

index 2b58fa713267c2ce68369613d468a88bb60fc295..0c3f597a0a5a2692dd3fe7a29fa103c786bd1d7e 100644 (file)
@@ -1,5 +1,5 @@
 --TEST--
-Try catch finally
+Try catch finally (basic test)
 --FILE--
 <?php
 function foo ($throw = FALSE) {
index 5f36ae2aa8b480f7d9396ecf5adae837114e851d..c54477ff8ccedaabc99b52f83e408acb8de87e78 100644 (file)
@@ -1,5 +1,5 @@
 --TEST--
-Try catch finally return
+Try catch finally (basic test with return)
 --FILE--
 <?php
 function foo () {
index a47c6f0f2c3c5ce8ccaf8dc57a126d1cbad33347..24e468d335c33b9b76348d0382a1d3e8fb4e0fde 100644 (file)
@@ -1,5 +1,5 @@
 --TEST--
-Try catch finally multi-return
+Try catch finally (with multi-returns)
 --FILE--
 <?php
 function dummy($msg) {
index be32a435c3aff4d5a98016202f475528035aab12..a2c22beab1182633cd745f0aef35f9670aa15fa2 100644 (file)
@@ -1,5 +1,5 @@
 --TEST--
-Nesting try catch finally
+Try catch finally (nesting try-catch-finally)
 --FILE--
 <?php
 
index d8573bd4e28c2d8a48bb553d32dacd46c8b6e9f6..c2fd55df27b1ccec7ab3924caae287d3dc54940f 100644 (file)
@@ -1,5 +1,5 @@
 --TEST--
-Try catch finally with return
+Try catch finally (with multi-returns and exception)
 --FILE--
 <?php
 function foo ($a) {
index 48937c40d44d2d80b597c1b0eec307e3eabca9aa..9759eab37ef11571ec5051ab0065a1ace89fc750 100644 (file)
@@ -1,5 +1,5 @@
 --TEST--
-Try catch finally: re-throw exception in catch block
+Try catch finally (re-throw exception in catch block)
 --FILE--
 <?php
 function foo ($a) {
diff --git a/Zend/tests/try_catch_finally_005.phpt b/Zend/tests/try_catch_finally_005.phpt
new file mode 100644 (file)
index 0000000..dafeb6b
--- /dev/null
@@ -0,0 +1,52 @@
+--TEST--
+Try catch finally (break / cont in try block)
+--CREDITS--
+adoy
+--FILE--
+<?php
+for ($i = 0;  $i < 100 ; $i ++) {
+    try {
+        break;
+    } finally {
+        var_dump("break");
+    }
+}
+
+
+for ($i = 0;  $i < 2; $i ++) {
+    try {
+        continue;
+    } finally {
+        var_dump("continue1");
+    }
+}
+
+for ($i = 0;  $i < 3; $i ++) {
+    try {
+        try {
+            continue;
+        } finally {
+            var_dump("continue2");
+            if ($i == 1) {
+                throw new Exception("continue exception");
+            }
+        }
+    } catch (Exception $e) {
+       var_dump("cactched");
+    }  finally {
+       var_dump("finally");
+    }
+}
+
+?>
+--EXPECTF--
+string(5) "break"
+string(9) "continue1"
+string(9) "continue1"
+string(9) "continue2"
+string(7) "finally"
+string(9) "continue2"
+string(8) "cactched"
+string(7) "finally"
+string(9) "continue2"
+string(7) "finally"
diff --git a/Zend/tests/try_catch_finally_006.phpt b/Zend/tests/try_catch_finally_006.phpt
new file mode 100644 (file)
index 0000000..dab6af6
--- /dev/null
@@ -0,0 +1,39 @@
+--TEST--
+Try catch finally (goto in try/catch block)
+--CREDITS--
+adoy
+--FILE--
+<?php
+function foo($ex = NULL) {
+    try {
+        try {
+            goto label;
+        } finally {
+            var_dump("finally1");
+            if ($ex) throw $ex;
+        } 
+    } catch (Exception $e) {
+       var_dump("catched");
+       if ($ex) return "return1";
+    } finally {
+       var_dump("finally2");
+    }
+
+label:
+   var_dump("label");
+   return "return2";
+}
+
+var_dump(foo());
+var_dump(foo(new Exception()));
+
+?>
+--EXPECTF--
+string(8) "finally1"
+string(8) "finally2"
+string(5) "label"
+string(7) "return2"
+string(8) "finally1"
+string(7) "catched"
+string(8) "finally2"
+string(7) "return1"
diff --git a/Zend/tests/try_catch_finally_007.phpt b/Zend/tests/try_catch_finally_007.phpt
new file mode 100644 (file)
index 0000000..ad33c68
--- /dev/null
@@ -0,0 +1,46 @@
+--TEST--
+Try catch finally (goto in try/catch block)
+--CREDITS--
+adoy
+--FILE--
+<?php
+function foo($ret = FALSE) {
+    try {
+        try {
+            do {
+                goto label;
+            } while(0);
+            foreach (array() as $val) {
+                continue;
+            }
+        } finally {
+            var_dump("finally1");
+            throw new Exception("exception");
+        } 
+    } catch (Exception $e) {
+        goto local;
+local: 
+        var_dump("catched");
+        if ($ret) return "return";
+    } finally {
+       var_dump("finally2");
+    }
+
+label:
+   var_dump("label");
+}
+
+var_dump(foo());
+var_dump(foo(true));
+
+?>
+--EXPECTF--
+string(8) "finally1"
+string(7) "catched"
+string(8) "finally2"
+string(5) "label"
+NULL
+string(8) "finally1"
+string(7) "catched"
+string(8) "finally2"
+string(6) "return"
index 1c168da275cdd288911bd5018e3ceb92a026cbcb..0f740872c2acdbc076c39724d901ad86d0422805 100644 (file)
@@ -1,5 +1,5 @@
 --TEST--
-Try finally
+Try finally (basic test)
 --FILE--
 <?php
 function foo ($a) {
@@ -20,4 +20,3 @@ Stack trace:
 #0 %stry_finally_001.php(%d): foo('finally')
 #1 {main}
   thrown in %stry_finally_001.php on line %d
-
index 44676966fe25918d63606820581f38c4ed949ec1..99a34f62fbd7a71a1b181456a9f7c14bfd232ecc 100644 (file)
@@ -1,5 +1,5 @@
 --TEST--
-Try finally
+Try finally (re-throw exception in finally block)
 --FILE--
 <?php
 function foo () {
index c5a380995ab264597d0defb054cc566173a8255d..c1294911bd330c87d53bbab0058fbefb86b0ba1b 100644 (file)
@@ -1,5 +1,5 @@
 --TEST--
-Try finally
+Try finally (call sequence test)
 --FILE--
 <?php
 function foo () {
index 8caa8fb18f7b7860463081c40d23d80856132316..08930a40c524418928928802fd47895fb7c98c78 100644 (file)
@@ -1,5 +1,5 @@
 --TEST--
-Try without catch/finally block
+Try finally (without catch/finally block)
 --FILE--
 <?php
 function foo () {
index 2c6c2c9e6ce4559bc0155e78bef8dd7e0088bab9..8664d6b1bf9a83d31f8d72933266a19300782851 100644 (file)
@@ -1,5 +1,5 @@
 --TEST--
-Finally with long goto
+Try finally (with long goto)
 --FILE--
 <?php
 function foo () {
index 2bfa4caea9c39c355b8e8701d92370c3aa867531..f53e6b5bc1e84e99566c51cbf2530f6a883da1e9 100644 (file)
@@ -1,5 +1,5 @@
 --TEST--
-Finally with near goto
+Try finally (with near goto)
 --FILE--
 <?php
 function foo () {
index b13bd59e508bb456844b2839b659b58996c8b34b..634937495c3139c2c6a92efb30958c5ca29e55ce 100644 (file)
@@ -1,5 +1,5 @@
 --TEST--
-Finally with goto previous label
+Try finally (with goto previous label)
 --FILE--
 <?php
 function foo () {
index 9025d8824dac364be40629249ba5679315214020..cee37aedabfc20f3647eb005f34701d3e8ddc5fe 100644 (file)
@@ -1,5 +1,5 @@
 --TEST--
-Finally with jmp (do while)
+Try finally (with break in do...while)
 --FILE--
 <?php
 function foo () {
index 7c3da6760b6ae054bbad3ea35cd5bf3c2240a03f..b29930a75e48266f192925e406a2dc5db2a1709c 100644 (file)
@@ -1,5 +1,5 @@
 --TEST--
-Finally with jmp (for continue)
+Try finally (with for continue)
 --FILE--
 <?php
 function foo () {
index 2ae8cc510f390aa20c29786358eff23724b6b9d1..cb0be0890ab857588ffee5a58a8fe3da627005ae 100644 (file)
@@ -2696,7 +2696,7 @@ void zend_initialize_try_catch_element(znode *catch_token TSRMLS_DC) /* {{{ */
        zend_stack_top(&CG(bp_stack), (void **) &jmp_list_ptr);
        zend_llist_add_element(jmp_list_ptr, &jmp_op_number);
 
-    catch_token->EA = get_next_op_number(CG(active_op_array));
+       catch_token->EA = get_next_op_number(CG(active_op_array));
 }
 /* }}} */
 
@@ -2792,7 +2792,7 @@ void zend_do_end_finally(znode *try_token, znode* catch_token, znode *finally_to
                zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
                CG(active_op_array)->try_catch_array[try_token->u.op.opline_num].finally_op = finally_token->u.op.opline_num;
                CG(active_op_array)->try_catch_array[try_token->u.op.opline_num].finally_end = get_next_op_number(CG(active_op_array));
-        CG(active_op_array)->has_finally_block = 1;
+               CG(active_op_array)->has_finally_block = 1;
 
                opline->opcode = ZEND_LEAVE;
                SET_UNUSED(opline->op1);
@@ -4059,9 +4059,9 @@ static void zend_traits_init_trait_structures(zend_class_entry *ce TSRMLS_DC) /*
 
                                /** And, ensure that the referenced method is resolvable, too. */
                                lcname = zend_str_tolower_dup(cur_method_ref->method_name,
-                                      cur_method_ref->mname_len);
+                                               cur_method_ref->mname_len);
                                method_exists = zend_hash_exists(&cur_method_ref->ce->function_table,
-                                         lcname, cur_method_ref->mname_len + 1);
+                                               lcname, cur_method_ref->mname_len + 1);
                                efree(lcname);
 
                                if (!method_exists) {
@@ -5043,11 +5043,11 @@ void zend_do_begin_class_declaration(const znode *class_token, znode *class_name
        opline->op2_type = IS_CONST;
 
        if (doing_inheritance) {
-       /* Make sure a trait does not try to extend a class */
-       if ((new_class_entry->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) {
-           zend_error(E_COMPILE_ERROR, "A trait (%s) cannot extend a class. Traits can only be composed from other traits with the 'use' keyword. Error", new_class_entry->name);
-       }
-    
+               /* Make sure a trait does not try to extend a class */
+               if ((new_class_entry->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) {
+                       zend_error(E_COMPILE_ERROR, "A trait (%s) cannot extend a class. Traits can only be composed from other traits with the 'use' keyword. Error", new_class_entry->name);
+               }
+
                opline->extended_value = parent_class_name->u.op.var;
                opline->opcode = ZEND_DECLARE_INHERITED_CLASS;
        } else {
@@ -6998,9 +6998,9 @@ void zend_do_use(znode *ns_name, znode *new_name, int is_global TSRMLS_DC) /* {{
        lcname = zend_str_tolower_dup(Z_STRVAL_P(name), Z_STRLEN_P(name));
 
        if (((Z_STRLEN_P(name) == sizeof("self")-1) &&
-          !memcmp(lcname, "self", sizeof("self")-1)) ||
-           ((Z_STRLEN_P(name) == sizeof("parent")-1) &&
-          !memcmp(lcname, "parent", sizeof("parent")-1))) {
+                               !memcmp(lcname, "self", sizeof("self")-1)) ||
+                       ((Z_STRLEN_P(name) == sizeof("parent")-1) &&
+          !memcmp(lcname, "parent", sizeof("parent")-1))) {
                zend_error(E_COMPILE_ERROR, "Cannot use %s as %s because '%s' is a special class name", Z_STRVAL_P(ns), Z_STRVAL_P(name), Z_STRVAL_P(name));
        }
 
index 80e02ab3098b89071c7098b12a31ef2db8967661..971860602eeaf88fe89245ef28f712705b93fb31 100644 (file)
@@ -281,7 +281,7 @@ struct _zend_op_array {
 
        zend_try_catch_element *try_catch_array;
        int last_try_catch;
-    zend_bool has_finally_block;
+       zend_bool has_finally_block;
 
        /* static variables support */
        HashTable *static_variables;
@@ -384,8 +384,8 @@ struct _zend_execute_data {
        zend_class_entry *current_called_scope;
        zval *current_this;
        zval *current_object;
-    zend_uint leaving;
-    zend_uint leaving_dest;
+       zend_uint leaving;
+       zend_uint leaving_dest;
 };
 
 #define EX(element) execute_data.element
index 2552d2ebd64ab3b0b8e1b8a15afbd9e0efb8339c..6c158291004315270adeeefc9ea58a7a30cb7598 100644 (file)
@@ -87,7 +87,7 @@ void init_op_array(zend_op_array *op_array, zend_uchar type, int initial_ops_siz
 
        op_array->static_variables = NULL;
        op_array->last_try_catch = 0;
-    op_array->has_finally_block = 0;
+       op_array->has_finally_block = 0;
 
        op_array->this_var = -1;
 
@@ -552,8 +552,8 @@ ZEND_API int pass_two(zend_op_array *op_array TSRMLS_DC)
                                }
                                opline->op1.jmp_addr = &op_array->opcodes[opline->op1.opline_num];
                                break;
-            case ZEND_BRK:
-            case ZEND_CONT:
+                       case ZEND_BRK:
+                       case ZEND_CONT:
                                if (op_array->last_try_catch) {
                                        int nest_levels, array_offset;
                                        zend_brk_cont_element *jmp_to;
index d921f81efc607cc35f066716ed7381d387ce863a..ce1674e4f3834cccd07e9c73f256e658fab56d7d 100644 (file)
@@ -1840,240 +1840,630 @@ ZEND_VM_HANDLER(39, ZEND_ASSIGN_REF, VAR|CV, VAR|CV)
        ZEND_VM_NEXT_OPCODE();
 }
 
-ZEND_VM_HANDLER(42, ZEND_JMP, ANY, ANY)
+ZEND_VM_HELPER(zend_leave_helper, ANY, ANY)
 {
-       USE_OPLINE
+       zend_bool nested;
+       zend_op_array *op_array = EX(op_array);
 
-#if DEBUG_ZEND>=2
-       printf("Jumping to %d\n", opline->op1.opline_num);
-#endif
-       ZEND_VM_SET_OPCODE(opline->op1.jmp_addr);
-       ZEND_VM_CONTINUE(); /* CHECK_ME */
-}
+       EG(current_execute_data) = EX(prev_execute_data);
+       EG(opline_ptr) = NULL;
+       if (!EG(active_symbol_table)) {
+               zval ***cv = EX_CVs();
+               zval ***end = cv + op_array->last_var;
+               while (cv != end) {
+                       if (*cv) {
+                               zval_ptr_dtor(*cv);
+                       }
+                       cv++;
+               }
+       }
 
-ZEND_VM_HANDLER(43, ZEND_JMPZ, CONST|TMP|VAR|CV, ANY)
-{
-       USE_OPLINE
-       zend_free_op free_op1;
-       zval *val;
-       int ret;
+       if ((op_array->fn_flags & ZEND_ACC_CLOSURE) && op_array->prototype) {
+               zval_ptr_dtor((zval**)&op_array->prototype);
+       }
 
-       SAVE_OPLINE();
-       val = GET_OP1_ZVAL_PTR(BP_VAR_R);
+       nested = EX(nested);
 
-       if (OP1_TYPE == IS_TMP_VAR && EXPECTED(Z_TYPE_P(val) == IS_BOOL)) {
-               ret = Z_LVAL_P(val);
-       } else {
-               ret = i_zend_is_true(val);
-               FREE_OP1();
-               if (UNEXPECTED(EG(exception) != NULL)) {
-                       HANDLE_EXCEPTION();
-               }
-       }
-       if (!ret) {
-#if DEBUG_ZEND>=2
-               printf("Conditional jmp to %d\n", opline->op2.opline_num);
-#endif
-               ZEND_VM_SET_OPCODE(opline->op2.jmp_addr);
-               ZEND_VM_CONTINUE();
+       zend_vm_stack_free(execute_data TSRMLS_CC);
+
+       if (nested) {
+               execute_data = EG(current_execute_data);
        }
+       if (nested) {
+               USE_OPLINE
 
-       ZEND_VM_NEXT_OPCODE();
-}
+               LOAD_REGS();
+               LOAD_OPLINE();
+               if (UNEXPECTED(opline->opcode == ZEND_INCLUDE_OR_EVAL)) {
 
-ZEND_VM_HANDLER(44, ZEND_JMPNZ, CONST|TMP|VAR|CV, ANY)
-{
-       USE_OPLINE
-       zend_free_op free_op1;
-       zval *val;
-       int ret;
+                       EX(function_state).function = (zend_function *) EX(op_array);
+                       EX(function_state).arguments = NULL;
+                       EX(object) = EX(current_object);
 
-       SAVE_OPLINE();
-       val = GET_OP1_ZVAL_PTR(BP_VAR_R);
+                       EG(opline_ptr) = &EX(opline);
+                       EG(active_op_array) = EX(op_array);
+                       EG(return_value_ptr_ptr) = EX(original_return_value);
+                       destroy_op_array(op_array TSRMLS_CC);
+                       efree(op_array);
+                       if (UNEXPECTED(EG(exception) != NULL)) {
+                               zend_throw_exception_internal(NULL TSRMLS_CC);
+                               HANDLE_EXCEPTION_LEAVE();
+                       } else if (RETURN_VALUE_USED(opline)) {
+                               if (!EX_T(opline->result.var).var.ptr) { /* there was no return statement */
+                                       zval *retval;
 
-       if (OP1_TYPE == IS_TMP_VAR && EXPECTED(Z_TYPE_P(val) == IS_BOOL)) {
-               ret = Z_LVAL_P(val);
-       } else {
-               ret = i_zend_is_true(val);
-               FREE_OP1();
-               if (UNEXPECTED(EG(exception) != NULL)) {
-                       HANDLE_EXCEPTION();
-               }
-       }
-       if (ret) {
-#if DEBUG_ZEND>=2
-               printf("Conditional jmp to %d\n", opline->op2.opline_num);
-#endif
-               ZEND_VM_SET_OPCODE(opline->op2.jmp_addr);
-               ZEND_VM_CONTINUE();
-       }
+                                       ALLOC_ZVAL(retval);
+                                       ZVAL_BOOL(retval, 1);
+                                       INIT_PZVAL(retval);
+                                       EX_T(opline->result.var).var.ptr = retval;
+                               }
+                       }
 
-       ZEND_VM_NEXT_OPCODE();
-}
+                       ZEND_VM_INC_OPCODE();
+                       ZEND_VM_LEAVE();
+               } else {
 
-ZEND_VM_HANDLER(45, ZEND_JMPZNZ, CONST|TMP|VAR|CV, ANY)
-{
-       USE_OPLINE
-       zend_free_op free_op1;
-       zval *val;
-       int retval;
+                       EG(opline_ptr) = &EX(opline);
+                       EG(active_op_array) = EX(op_array);
+                       EG(return_value_ptr_ptr) = EX(original_return_value);
+                       if (EG(active_symbol_table)) {
+                               if (EG(symtable_cache_ptr)>=EG(symtable_cache_limit)) {
+                                       zend_hash_destroy(EG(active_symbol_table));
+                                       FREE_HASHTABLE(EG(active_symbol_table));
+                               } else {
+                                       /* clean before putting into the cache, since clean
+                                          could call dtors, which could use cached hash */
+                                       zend_hash_clean(EG(active_symbol_table));
+                                       *(++EG(symtable_cache_ptr)) = EG(active_symbol_table);
+                               }
+                       }
+                       EG(active_symbol_table) = EX(symbol_table);
 
-       SAVE_OPLINE();
-       val = GET_OP1_ZVAL_PTR(BP_VAR_R);
+                       EX(function_state).function = (zend_function *) EX(op_array);
+                       EX(function_state).arguments = NULL;
 
-       if (OP1_TYPE == IS_TMP_VAR && EXPECTED(Z_TYPE_P(val) == IS_BOOL)) {
-               retval = Z_LVAL_P(val);
-       } else {
-               retval = i_zend_is_true(val);
-               FREE_OP1();
-               if (UNEXPECTED(EG(exception) != NULL)) {
-                       HANDLE_EXCEPTION();
+                       if (EG(This)) {
+                               if (UNEXPECTED(EG(exception) != NULL) && IS_CTOR_CALL(EX(called_scope))) {
+                                       if (IS_CTOR_USED(EX(called_scope))) {
+                                               Z_DELREF_P(EG(This));
+                                       }
+                                       if (Z_REFCOUNT_P(EG(This)) == 1) {
+                                               zend_object_store_ctor_failed(EG(This) TSRMLS_CC);
+                                       }
+                               }
+                               zval_ptr_dtor(&EG(This));
+                       }
+                       EG(This) = EX(current_this);
+                       EG(scope) = EX(current_scope);
+                       EG(called_scope) = EX(current_called_scope);
+
+                       EX(object) = EX(current_object);
+                       EX(called_scope) = DECODE_CTOR(EX(called_scope));
+
+                       zend_vm_stack_clear_multiple(TSRMLS_C);
+
+                       if (UNEXPECTED(EG(exception) != NULL)) {
+                               zend_throw_exception_internal(NULL TSRMLS_CC);
+                               if (RETURN_VALUE_USED(opline) && EX_T(opline->result.var).var.ptr) {
+                                       zval_ptr_dtor(&EX_T(opline->result.var).var.ptr);
+                               }
+                               HANDLE_EXCEPTION_LEAVE();
+                       }
+
+                       ZEND_VM_INC_OPCODE();
+                       ZEND_VM_LEAVE();
                }
        }
-       if (EXPECTED(retval != 0)) {
-#if DEBUG_ZEND>=2
-               printf("Conditional jmp on true to %d\n", opline->extended_value);
-#endif
-               ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[opline->extended_value]);
-               ZEND_VM_CONTINUE(); /* CHECK_ME */
-       } else {
-#if DEBUG_ZEND>=2
-               printf("Conditional jmp on false to %d\n", opline->op2.opline_num);
-#endif
-               ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[opline->op2.opline_num]);
-               ZEND_VM_CONTINUE(); /* CHECK_ME */
-       }
+       ZEND_VM_RETURN();
 }
 
-ZEND_VM_HANDLER(46, ZEND_JMPZ_EX, CONST|TMP|VAR|CV, ANY)
+ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY)
 {
        USE_OPLINE
-       zend_free_op free_op1;
-       zval *val;
-       int retval;
+       zend_bool should_change_scope = 0;
+       zend_function *fbc = EX(function_state).function;
 
        SAVE_OPLINE();
-       val = GET_OP1_ZVAL_PTR(BP_VAR_R);
+       if (UNEXPECTED((fbc->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_DEPRECATED)) != 0)) {
+               if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_ABSTRACT) != 0)) {
+                       zend_error_noreturn(E_ERROR, "Cannot call abstract method %s::%s()", fbc->common.scope->name, fbc->common.function_name);
+                       CHECK_EXCEPTION();
+                       ZEND_VM_NEXT_OPCODE(); /* Never reached */
+               }
+               if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) {
+                       zend_error(E_DEPRECATED, "Function %s%s%s() is deprecated",
+                               fbc->common.scope ? fbc->common.scope->name : "",
+                               fbc->common.scope ? "::" : "",
+                               fbc->common.function_name);
+               }
+       }
+       if (fbc->common.scope &&
+               !(fbc->common.fn_flags & ZEND_ACC_STATIC) &&
+               !EX(object)) {
 
-       if (OP1_TYPE == IS_TMP_VAR && EXPECTED(Z_TYPE_P(val) == IS_BOOL)) {
-               retval = Z_LVAL_P(val);
-       } else {
-               retval = i_zend_is_true(val);
-               FREE_OP1();
-               if (UNEXPECTED(EG(exception) != NULL)) {
-                       HANDLE_EXCEPTION();
+               if (fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) {
+                       /* FIXME: output identifiers properly */
+                       zend_error(E_STRICT, "Non-static method %s::%s() should not be called statically", fbc->common.scope->name, fbc->common.function_name);
+               } else {
+                       /* FIXME: output identifiers properly */
+                       /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */
+                       zend_error_noreturn(E_ERROR, "Non-static method %s::%s() cannot be called statically", fbc->common.scope->name, fbc->common.function_name);
                }
        }
-       Z_LVAL(EX_T(opline->result.var).tmp_var) = retval;
-       Z_TYPE(EX_T(opline->result.var).tmp_var) = IS_BOOL;
-       if (!retval) {
-#if DEBUG_ZEND>=2
-               printf("Conditional jmp to %d\n", opline->op2.opline_num);
-#endif
-               ZEND_VM_SET_OPCODE(opline->op2.jmp_addr);
-               ZEND_VM_CONTINUE();
+
+       if (fbc->type == ZEND_USER_FUNCTION || fbc->common.scope) {
+               should_change_scope = 1;
+               EX(current_this) = EG(This);
+               EX(current_scope) = EG(scope);
+               EX(current_called_scope) = EG(called_scope);
+               EG(This) = EX(object);
+               EG(scope) = (fbc->type == ZEND_USER_FUNCTION || !EX(object)) ? fbc->common.scope : NULL;
+               EG(called_scope) = EX(called_scope);
        }
-       ZEND_VM_NEXT_OPCODE();
-}
 
-ZEND_VM_HANDLER(47, ZEND_JMPNZ_EX, CONST|TMP|VAR|CV, ANY)
-{
-       USE_OPLINE
-       zend_free_op free_op1;
-       zval *val;
-       int retval;
+       zend_arg_types_stack_3_pop(&EG(arg_types_stack), &EX(called_scope), &EX(current_object), &EX(fbc));
+       EX(function_state).arguments = zend_vm_stack_push_args(opline->extended_value TSRMLS_CC);
+       LOAD_OPLINE();
 
-       SAVE_OPLINE();
-       val = GET_OP1_ZVAL_PTR(BP_VAR_R);
+       if (fbc->type == ZEND_INTERNAL_FUNCTION) {
+               temp_variable *ret = &EX_T(opline->result.var);
 
-       if (OP1_TYPE == IS_TMP_VAR && EXPECTED(Z_TYPE_P(val) == IS_BOOL)) {
-               retval = Z_LVAL_P(val);
-       } else {
-               retval = i_zend_is_true(val);
-               FREE_OP1();
-               if (UNEXPECTED(EG(exception) != NULL)) {
-                       HANDLE_EXCEPTION();
+               MAKE_STD_ZVAL(ret->var.ptr);
+               ZVAL_NULL(ret->var.ptr);
+               ret->var.ptr_ptr = &ret->var.ptr;
+               ret->var.fcall_returned_reference = (fbc->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0;
+
+               if (fbc->common.arg_info) {
+                       zend_uint i=0;
+                       zval **p = (zval**)EX(function_state).arguments;
+                       ulong arg_count = opline->extended_value;
+
+                       while (arg_count>0) {
+                               zend_verify_arg_type(fbc, ++i, *(p-arg_count), 0 TSRMLS_CC);
+                               arg_count--;
+                       }
+               }
+
+               if (!zend_execute_internal) {
+                       /* saves one function call if zend_execute_internal is not used */
+                       fbc->internal_function.handler(opline->extended_value, ret->var.ptr, (fbc->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) ? &ret->var.ptr : NULL, EX(object), RETURN_VALUE_USED(opline) TSRMLS_CC);
+               } else {
+                       zend_execute_internal(EXECUTE_DATA, RETURN_VALUE_USED(opline) TSRMLS_CC);
+               }
+
+               if (!RETURN_VALUE_USED(opline)) {
+                       zval_ptr_dtor(&ret->var.ptr);
+               }
+       } else if (fbc->type == ZEND_USER_FUNCTION) {
+               EX(original_return_value) = EG(return_value_ptr_ptr);
+               EG(active_symbol_table) = NULL;
+               EG(active_op_array) = &fbc->op_array;
+               EG(return_value_ptr_ptr) = NULL;
+               if (RETURN_VALUE_USED(opline)) {
+                       temp_variable *ret = &EX_T(opline->result.var);
+
+                       ret->var.ptr = NULL;
+                       EG(return_value_ptr_ptr) = &ret->var.ptr;
+                       ret->var.ptr_ptr = &ret->var.ptr;
+                       ret->var.fcall_returned_reference = (fbc->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0;
+               }
+
+               if (EXPECTED(zend_execute == execute)) {
+                       if (EXPECTED(EG(exception) == NULL)) {
+                               ZEND_VM_ENTER();
+                       }
+               } else {
+                       zend_execute(EG(active_op_array) TSRMLS_CC);
+               }
+
+               EG(opline_ptr) = &EX(opline);
+               EG(active_op_array) = EX(op_array);
+               EG(return_value_ptr_ptr) = EX(original_return_value);
+               if (EG(active_symbol_table)) {
+                       if (EG(symtable_cache_ptr)>=EG(symtable_cache_limit)) {
+                               zend_hash_destroy(EG(active_symbol_table));
+                               FREE_HASHTABLE(EG(active_symbol_table));
+                       } else {
+                               /* clean before putting into the cache, since clean
+                                  could call dtors, which could use cached hash */
+                               zend_hash_clean(EG(active_symbol_table));
+                               *(++EG(symtable_cache_ptr)) = EG(active_symbol_table);
+                       }
+               }
+               EG(active_symbol_table) = EX(symbol_table);
+       } else { /* ZEND_OVERLOADED_FUNCTION */
+               MAKE_STD_ZVAL(EX_T(opline->result.var).var.ptr);
+               ZVAL_NULL(EX_T(opline->result.var).var.ptr);
+
+                       /* Not sure what should be done here if it's a static method */
+               if (EXPECTED(EX(object) != NULL)) {
+                       Z_OBJ_HT_P(EX(object))->call_method(fbc->common.function_name, opline->extended_value, EX_T(opline->result.var).var.ptr, &EX_T(opline->result.var).var.ptr, EX(object), RETURN_VALUE_USED(opline) TSRMLS_CC);
+               } else {
+                       zend_error_noreturn(E_ERROR, "Cannot call overloaded function for non-object");
+               }
+
+               if (fbc->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) {
+                       efree((char*)fbc->common.function_name);
+               }
+               efree(fbc);
+
+               if (!RETURN_VALUE_USED(opline)) {
+                       zval_ptr_dtor(&EX_T(opline->result.var).var.ptr);
+               } else {
+                       Z_UNSET_ISREF_P(EX_T(opline->result.var).var.ptr);
+                       Z_SET_REFCOUNT_P(EX_T(opline->result.var).var.ptr, 1);
+                       EX_T(opline->result.var).var.fcall_returned_reference = 0;
+                       EX_T(opline->result.var).var.ptr_ptr = &EX_T(opline->result.var).var.ptr;
                }
        }
-       Z_LVAL(EX_T(opline->result.var).tmp_var) = retval;
-       Z_TYPE(EX_T(opline->result.var).tmp_var) = IS_BOOL;
-       if (retval) {
-#if DEBUG_ZEND>=2
-               printf("Conditional jmp to %d\n", opline->op2.opline_num);
-#endif
-               ZEND_VM_SET_OPCODE(opline->op2.jmp_addr);
-               ZEND_VM_CONTINUE();
+
+       EX(function_state).function = (zend_function *) EX(op_array);
+       EX(function_state).arguments = NULL;
+
+       if (should_change_scope) {
+               if (EG(This)) {
+                       if (UNEXPECTED(EG(exception) != NULL) && IS_CTOR_CALL(EX(called_scope))) {
+                               if (IS_CTOR_USED(EX(called_scope))) {
+                                       Z_DELREF_P(EG(This));
+                               }
+                               if (Z_REFCOUNT_P(EG(This)) == 1) {
+                                       zend_object_store_ctor_failed(EG(This) TSRMLS_CC);
+                               }
+                       }
+                       zval_ptr_dtor(&EG(This));
+               }
+               EG(This) = EX(current_this);
+               EG(scope) = EX(current_scope);
+               EG(called_scope) = EX(current_called_scope);
+       }
+
+       EX(object) = EX(current_object);
+       EX(called_scope) = DECODE_CTOR(EX(called_scope));
+
+       zend_vm_stack_clear_multiple(TSRMLS_C);
+
+       if (UNEXPECTED(EG(exception) != NULL)) {
+               zend_throw_exception_internal(NULL TSRMLS_CC);
+               if (RETURN_VALUE_USED(opline) && EX_T(opline->result.var).var.ptr) {
+                       zval_ptr_dtor(&EX_T(opline->result.var).var.ptr);
+               }
+               HANDLE_EXCEPTION();
        }
+
        ZEND_VM_NEXT_OPCODE();
 }
 
-ZEND_VM_HANDLER(70, ZEND_FREE, TMP|VAR, ANY)
+ZEND_VM_HELPER_EX(zend_finally_handler_leaving, ANY, ANY, int type)
 {
        USE_OPLINE
+       zend_uint i, op_num = opline - EX(op_array)->opcodes;
+       zend_uint catch_op_num = 0, finally_op_num = 0;
 
        SAVE_OPLINE();
-       if (OP1_TYPE == IS_TMP_VAR) {
-               zendi_zval_dtor(EX_T(opline->op1.var).tmp_var);
-       } else {
-               zval_ptr_dtor(&EX_T(opline->op1.var).var.ptr);
+
+       switch (type) {
+               case ZEND_THROW:
+               case ZEND_RETURN:
+               case ZEND_RETURN_BY_REF:
+               case ZEND_LEAVE:
+                       {
+                               if (EG(prev_exception) || (type == ZEND_LEAVE && EG(exception))) {
+                                       for (i=0; i<EX(op_array)->last_try_catch; i++) {
+                                               if (EX(op_array)->try_catch_array[i].try_op > op_num) {
+                                                       break;
+                                               } 
+                                               if (op_num < EX(op_array)->try_catch_array[i].finally_op) {
+                                                       finally_op_num = EX(op_array)->try_catch_array[i].finally_op;
+                                               }
+                                               if (op_num < EX(op_array)->try_catch_array[i].catch_op) {
+                                                       catch_op_num = EX(op_array)->try_catch_array[i].catch_op;
+                                               }
+                                       }
+                               } else {
+                                       for (i=0; i<EX(op_array)->last_try_catch; i++) {
+                                               if (EX(op_array)->try_catch_array[i].try_op > op_num) {
+                                                       break;
+                                               } 
+                                               if (op_num < EX(op_array)->try_catch_array[i].finally_op) {
+                                                       finally_op_num = EX(op_array)->try_catch_array[i].finally_op;
+                                               }
+                                       }
+                               }
+
+                               if (catch_op_num && finally_op_num) {
+                                       /* EG(exception) || EG(prev_exception) */
+                                       if (catch_op_num > finally_op_num) {
+                                               EX(leaving) = ZEND_THROW;
+                                               ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[finally_op_num]);
+                                       } else {
+                                               EX(leaving) = 0;
+                                               ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[catch_op_num]);
+                                       }
+                               } else if (catch_op_num) {
+                                       EX(leaving) = 0;
+                                       ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[catch_op_num]);
+                               } else if (finally_op_num) {
+                                       if (type != ZEND_LEAVE) {
+                                               EX(leaving) = type;
+                                       }
+                                       ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[finally_op_num]);
+                               } else if (EX(leaving) && type != ZEND_LEAVE) {
+                                       /* leave it to ZEND_LEAVE */
+                                       EX(leaving) = type;
+                                       ZEND_VM_NEXT_OPCODE();
+                               } else {
+                                       ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper);
+                               }
+                       }
+                       break;
+               case ZEND_JMP:
+               case ZEND_BRK:
+               case ZEND_CONT:
+               case ZEND_GOTO:
+                       {
+                 /* these can not occurred in exception context */
+                 for (i=0; i<EG(active_op_array)->last_try_catch; i++) {
+                         if (EG(active_op_array)->try_catch_array[i].try_op > op_num) {
+                                 break;
+                         } 
+                         if (op_num < EG(active_op_array)->try_catch_array[i].finally_op 
+                                         && (EX(leaving_dest) < EG(active_op_array)->try_catch_array[i].try_op
+                                                 || EX(leaving_dest) >= EG(active_op_array)->try_catch_array[i].finally_end)) {
+                                 finally_op_num = EG(active_op_array)->try_catch_array[i].finally_op;
+                         }
+                 }
+
+                 if (finally_op_num) {
+                         EX(leaving) = type;
+                         ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[finally_op_num]);
+                 } else {
+                         EX(leaving) = 0;
+                         ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[EX(leaving_dest)]);
+                 }
+         }
+                       break;
        }
-       CHECK_EXCEPTION();
-       ZEND_VM_NEXT_OPCODE();
+       ZEND_VM_CONTINUE();
 }
 
-ZEND_VM_HANDLER(53, ZEND_INIT_STRING, ANY, ANY)
+ZEND_VM_HANDLER(42, ZEND_JMP, ANY, ANY)
 {
        USE_OPLINE
-       zval *tmp = &EX_T(opline->result.var).tmp_var;
 
-       SAVE_OPLINE();
-       tmp->value.str.val = emalloc(1);
-       tmp->value.str.val[0] = 0;
-       tmp->value.str.len = 0;
-       Z_SET_REFCOUNT_P(tmp, 1);
-       tmp->type = IS_STRING;
-       Z_UNSET_ISREF_P(tmp);
-       /*CHECK_EXCEPTION();*/
-       ZEND_VM_NEXT_OPCODE();
+#if DEBUG_ZEND>=2
+       printf("Jumping to %d\n", opline->op1.opline_num);
+#endif
+       if (EX(op_array)->has_finally_block) {
+               EX(leaving_dest) = opline->op1.jmp_addr - EX(op_array)->opcodes;
+               ZEND_VM_DISPATCH_TO_HELPER_EX(zend_finally_handler_leaving, type, ZEND_JMP);
+       }
+       ZEND_VM_SET_OPCODE(opline->op1.jmp_addr);
+       ZEND_VM_CONTINUE(); /* CHECK_ME */
 }
 
-ZEND_VM_HANDLER(54, ZEND_ADD_CHAR, TMP|UNUSED, CONST)
+ZEND_VM_HANDLER(43, ZEND_JMPZ, CONST|TMP|VAR|CV, ANY)
 {
        USE_OPLINE
-       zval *str = &EX_T(opline->result.var).tmp_var;
+       zend_free_op free_op1;
+       zval *val;
+       int ret;
 
        SAVE_OPLINE();
+       val = GET_OP1_ZVAL_PTR(BP_VAR_R);
 
-       if (OP1_TYPE == IS_UNUSED) {
-               /* Initialize for erealloc in add_char_to_string */
-               Z_STRVAL_P(str) = NULL;
-               Z_STRLEN_P(str) = 0;
-               Z_TYPE_P(str) = IS_STRING;
-
-               INIT_PZVAL(str);
+       if (OP1_TYPE == IS_TMP_VAR && EXPECTED(Z_TYPE_P(val) == IS_BOOL)) {
+               ret = Z_LVAL_P(val);
+       } else {
+               ret = i_zend_is_true(val);
+               FREE_OP1();
+               if (UNEXPECTED(EG(exception) != NULL)) {
+                       HANDLE_EXCEPTION();
+               }
+       }
+       if (!ret) {
+#if DEBUG_ZEND>=2
+               printf("Conditional jmp to %d\n", opline->op2.opline_num);
+#endif
+               ZEND_VM_SET_OPCODE(opline->op2.jmp_addr);
+               ZEND_VM_CONTINUE();
        }
 
-       add_char_to_string(str, str, opline->op2.zv);
-
-       /* FREE_OP is missing intentionally here - we're always working on the same temporary variable */
-       /*CHECK_EXCEPTION();*/
        ZEND_VM_NEXT_OPCODE();
 }
 
-ZEND_VM_HANDLER(55, ZEND_ADD_STRING, TMP|UNUSED, CONST)
+ZEND_VM_HANDLER(44, ZEND_JMPNZ, CONST|TMP|VAR|CV, ANY)
 {
        USE_OPLINE
-       zval *str = &EX_T(opline->result.var).tmp_var;
+       zend_free_op free_op1;
+       zval *val;
+       int ret;
 
        SAVE_OPLINE();
+       val = GET_OP1_ZVAL_PTR(BP_VAR_R);
 
-       if (OP1_TYPE == IS_UNUSED) {
-               /* Initialize for erealloc in add_string_to_string */
-               Z_STRVAL_P(str) = NULL;
-               Z_STRLEN_P(str) = 0;
-               Z_TYPE_P(str) = IS_STRING;
-
-               INIT_PZVAL(str);
+       if (OP1_TYPE == IS_TMP_VAR && EXPECTED(Z_TYPE_P(val) == IS_BOOL)) {
+               ret = Z_LVAL_P(val);
+       } else {
+               ret = i_zend_is_true(val);
+               FREE_OP1();
+               if (UNEXPECTED(EG(exception) != NULL)) {
+                       HANDLE_EXCEPTION();
+               }
+       }
+       if (ret) {
+#if DEBUG_ZEND>=2
+               printf("Conditional jmp to %d\n", opline->op2.opline_num);
+#endif
+               ZEND_VM_SET_OPCODE(opline->op2.jmp_addr);
+               ZEND_VM_CONTINUE();
+       }
+
+       ZEND_VM_NEXT_OPCODE();
+}
+
+ZEND_VM_HANDLER(45, ZEND_JMPZNZ, CONST|TMP|VAR|CV, ANY)
+{
+       USE_OPLINE
+       zend_free_op free_op1;
+       zval *val;
+       int retval;
+
+       SAVE_OPLINE();
+       val = GET_OP1_ZVAL_PTR(BP_VAR_R);
+
+       if (OP1_TYPE == IS_TMP_VAR && EXPECTED(Z_TYPE_P(val) == IS_BOOL)) {
+               retval = Z_LVAL_P(val);
+       } else {
+               retval = i_zend_is_true(val);
+               FREE_OP1();
+               if (UNEXPECTED(EG(exception) != NULL)) {
+                       HANDLE_EXCEPTION();
+               }
+       }
+       if (EXPECTED(retval != 0)) {
+#if DEBUG_ZEND>=2
+               printf("Conditional jmp on true to %d\n", opline->extended_value);
+#endif
+               ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[opline->extended_value]);
+               ZEND_VM_CONTINUE(); /* CHECK_ME */
+       } else {
+#if DEBUG_ZEND>=2
+               printf("Conditional jmp on false to %d\n", opline->op2.opline_num);
+#endif
+               ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[opline->op2.opline_num]);
+               ZEND_VM_CONTINUE(); /* CHECK_ME */
+       }
+}
+
+ZEND_VM_HANDLER(46, ZEND_JMPZ_EX, CONST|TMP|VAR|CV, ANY)
+{
+       USE_OPLINE
+       zend_free_op free_op1;
+       zval *val;
+       int retval;
+
+       SAVE_OPLINE();
+       val = GET_OP1_ZVAL_PTR(BP_VAR_R);
+
+       if (OP1_TYPE == IS_TMP_VAR && EXPECTED(Z_TYPE_P(val) == IS_BOOL)) {
+               retval = Z_LVAL_P(val);
+       } else {
+               retval = i_zend_is_true(val);
+               FREE_OP1();
+               if (UNEXPECTED(EG(exception) != NULL)) {
+                       HANDLE_EXCEPTION();
+               }
+       }
+       Z_LVAL(EX_T(opline->result.var).tmp_var) = retval;
+       Z_TYPE(EX_T(opline->result.var).tmp_var) = IS_BOOL;
+       if (!retval) {
+#if DEBUG_ZEND>=2
+               printf("Conditional jmp to %d\n", opline->op2.opline_num);
+#endif
+               ZEND_VM_SET_OPCODE(opline->op2.jmp_addr);
+               ZEND_VM_CONTINUE();
+       }
+       ZEND_VM_NEXT_OPCODE();
+}
+
+ZEND_VM_HANDLER(47, ZEND_JMPNZ_EX, CONST|TMP|VAR|CV, ANY)
+{
+       USE_OPLINE
+       zend_free_op free_op1;
+       zval *val;
+       int retval;
+
+       SAVE_OPLINE();
+       val = GET_OP1_ZVAL_PTR(BP_VAR_R);
+
+       if (OP1_TYPE == IS_TMP_VAR && EXPECTED(Z_TYPE_P(val) == IS_BOOL)) {
+               retval = Z_LVAL_P(val);
+       } else {
+               retval = i_zend_is_true(val);
+               FREE_OP1();
+               if (UNEXPECTED(EG(exception) != NULL)) {
+                       HANDLE_EXCEPTION();
+               }
+       }
+       Z_LVAL(EX_T(opline->result.var).tmp_var) = retval;
+       Z_TYPE(EX_T(opline->result.var).tmp_var) = IS_BOOL;
+       if (retval) {
+#if DEBUG_ZEND>=2
+               printf("Conditional jmp to %d\n", opline->op2.opline_num);
+#endif
+               ZEND_VM_SET_OPCODE(opline->op2.jmp_addr);
+               ZEND_VM_CONTINUE();
+       }
+       ZEND_VM_NEXT_OPCODE();
+}
+
+ZEND_VM_HANDLER(70, ZEND_FREE, TMP|VAR, ANY)
+{
+       USE_OPLINE
+
+       SAVE_OPLINE();
+       if (OP1_TYPE == IS_TMP_VAR) {
+               zendi_zval_dtor(EX_T(opline->op1.var).tmp_var);
+       } else {
+               zval_ptr_dtor(&EX_T(opline->op1.var).var.ptr);
+       }
+       CHECK_EXCEPTION();
+       ZEND_VM_NEXT_OPCODE();
+}
+
+ZEND_VM_HANDLER(53, ZEND_INIT_STRING, ANY, ANY)
+{
+       USE_OPLINE
+       zval *tmp = &EX_T(opline->result.var).tmp_var;
+
+       SAVE_OPLINE();
+       tmp->value.str.val = emalloc(1);
+       tmp->value.str.val[0] = 0;
+       tmp->value.str.len = 0;
+       Z_SET_REFCOUNT_P(tmp, 1);
+       tmp->type = IS_STRING;
+       Z_UNSET_ISREF_P(tmp);
+       /*CHECK_EXCEPTION();*/
+       ZEND_VM_NEXT_OPCODE();
+}
+
+ZEND_VM_HANDLER(54, ZEND_ADD_CHAR, TMP|UNUSED, CONST)
+{
+       USE_OPLINE
+       zval *str = &EX_T(opline->result.var).tmp_var;
+
+       SAVE_OPLINE();
+
+       if (OP1_TYPE == IS_UNUSED) {
+               /* Initialize for erealloc in add_char_to_string */
+               Z_STRVAL_P(str) = NULL;
+               Z_STRLEN_P(str) = 0;
+               Z_TYPE_P(str) = IS_STRING;
+
+               INIT_PZVAL(str);
+       }
+
+       add_char_to_string(str, str, opline->op2.zv);
+
+       /* FREE_OP is missing intentionally here - we're always working on the same temporary variable */
+       /*CHECK_EXCEPTION();*/
+       ZEND_VM_NEXT_OPCODE();
+}
+
+ZEND_VM_HANDLER(55, ZEND_ADD_STRING, TMP|UNUSED, CONST)
+{
+       USE_OPLINE
+       zval *str = &EX_T(opline->result.var).tmp_var;
+
+       SAVE_OPLINE();
+
+       if (OP1_TYPE == IS_UNUSED) {
+               /* Initialize for erealloc in add_string_to_string */
+               Z_STRVAL_P(str) = NULL;
+               Z_STRLEN_P(str) = 0;
+               Z_TYPE_P(str) = IS_STRING;
+
+               INIT_PZVAL(str);
        }
 
        add_string_to_string(str, str, opline->op2.zv);
@@ -2408,396 +2798,103 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMP|VAR|CV)
                            EX(fbc)->common.fn_flags & ZEND_ACC_CLOSURE) {
                                /* Delay closure destruction until its invocation */
                                EX(fbc)->common.prototype = (zend_function*)function_name;
-                       } else {
-                               FREE_OP2();
-                       }
-                       CHECK_EXCEPTION();
-                       ZEND_VM_NEXT_OPCODE();
-               } else if (OP2_TYPE != IS_CONST &&
-                               EXPECTED(Z_TYPE_P(function_name) == IS_ARRAY) &&
-                               zend_hash_num_elements(Z_ARRVAL_P(function_name)) == 2) {
-                       zend_class_entry *ce;
-                       zval **method = NULL;
-                       zval **obj = NULL;
-
-                       zend_hash_index_find(Z_ARRVAL_P(function_name), 0, (void **) &obj);
-                       zend_hash_index_find(Z_ARRVAL_P(function_name), 1, (void **) &method);
-
-                       if (Z_TYPE_PP(obj) != IS_STRING && Z_TYPE_PP(obj) != IS_OBJECT) {
-                               zend_error_noreturn(E_ERROR, "First array member is not a valid class name or object");
-                       }
-
-                       if (Z_TYPE_PP(method) != IS_STRING) {
-                               zend_error_noreturn(E_ERROR, "Second array member is not a valid method");
-                       }
-
-                       if (Z_TYPE_PP(obj) == IS_STRING) {
-                               ce = zend_fetch_class_by_name(Z_STRVAL_PP(obj), Z_STRLEN_PP(obj), NULL, 0 TSRMLS_CC);
-                               if (UNEXPECTED(ce == NULL)) {
-                                       CHECK_EXCEPTION();
-                                       ZEND_VM_NEXT_OPCODE();
-                               }
-                               EX(called_scope) = ce;
-                               EX(object) = NULL;
-
-                               if (ce->get_static_method) {
-                                       EX(fbc) = ce->get_static_method(ce, Z_STRVAL_PP(method), Z_STRLEN_PP(method) TSRMLS_CC);
-                               } else {
-                                       EX(fbc) = zend_std_get_static_method(ce, Z_STRVAL_PP(method), Z_STRLEN_PP(method), NULL TSRMLS_CC);
-                               }
-                       } else {
-                               EX(object) = *obj;
-                               ce = EX(called_scope) = Z_OBJCE_PP(obj);
-
-                               EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), Z_STRVAL_PP(method), Z_STRLEN_PP(method), NULL TSRMLS_CC);
-                               if (UNEXPECTED(EX(fbc) == NULL)) {
-                                       zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), Z_STRVAL_PP(method));
-                               }
-
-                               if ((EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) != 0) {
-                                       EX(object) = NULL;
-                               } else {
-                                       if (!PZVAL_IS_REF(EX(object))) {
-                                               Z_ADDREF_P(EX(object)); /* For $this pointer */
-                                       } else {
-                                               zval *this_ptr;
-                                               ALLOC_ZVAL(this_ptr);
-                                               INIT_PZVAL_COPY(this_ptr, EX(object));
-                                               zval_copy_ctor(this_ptr);
-                                               EX(object) = this_ptr;
-                                       }
-                               }
-                       }
-
-                       if (UNEXPECTED(EX(fbc) == NULL)) {
-                               zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name, Z_STRVAL_PP(method));
-                       }
-                       FREE_OP2();
-                       CHECK_EXCEPTION();
-                       ZEND_VM_NEXT_OPCODE();
-               } else {
-                       zend_error_noreturn(E_ERROR, "Function name must be a string");
-               }
-       }
-}
-
-
-ZEND_VM_HANDLER(69, ZEND_INIT_NS_FCALL_BY_NAME, ANY, CONST)
-{
-       USE_OPLINE
-       zend_literal *func_name;
-
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope));
-
-       func_name = opline->op2.literal + 1;
-       if (CACHED_PTR(opline->op2.literal->cache_slot)) {
-               EX(fbc) = CACHED_PTR(opline->op2.literal->cache_slot);
-       } else if (zend_hash_quick_find(EG(function_table), Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant)+1, func_name->hash_value, (void **) &EX(fbc))==FAILURE) {
-               func_name++;
-               if (UNEXPECTED(zend_hash_quick_find(EG(function_table), Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant)+1, func_name->hash_value, (void **) &EX(fbc))==FAILURE)) {
-                       SAVE_OPLINE();
-                       zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv));
-               } else {
-                       CACHE_PTR(opline->op2.literal->cache_slot, EX(fbc));
-               }
-       } else {
-               CACHE_PTR(opline->op2.literal->cache_slot, EX(fbc));
-       }
-
-       EX(object) = NULL;
-       ZEND_VM_NEXT_OPCODE();
-}
-
-ZEND_VM_HELPER(zend_leave_helper, ANY, ANY)
-{
-       zend_bool nested;
-       zend_op_array *op_array = EX(op_array);
-
-       EG(current_execute_data) = EX(prev_execute_data);
-       EG(opline_ptr) = NULL;
-       if (!EG(active_symbol_table)) {
-               zval ***cv = EX_CVs();
-               zval ***end = cv + op_array->last_var;
-               while (cv != end) {
-                       if (*cv) {
-                               zval_ptr_dtor(*cv);
-                       }
-                       cv++;
-               }
-       }
-
-       if ((op_array->fn_flags & ZEND_ACC_CLOSURE) && op_array->prototype) {
-               zval_ptr_dtor((zval**)&op_array->prototype);
-       }
-
-       nested = EX(nested);
-
-       zend_vm_stack_free(execute_data TSRMLS_CC);
-
-       if (nested) {
-               execute_data = EG(current_execute_data);
-       }
-       if (nested) {
-               USE_OPLINE
-
-               LOAD_REGS();
-               LOAD_OPLINE();
-               if (UNEXPECTED(opline->opcode == ZEND_INCLUDE_OR_EVAL)) {
-
-                       EX(function_state).function = (zend_function *) EX(op_array);
-                       EX(function_state).arguments = NULL;
-                       EX(object) = EX(current_object);
-
-                       EG(opline_ptr) = &EX(opline);
-                       EG(active_op_array) = EX(op_array);
-                       EG(return_value_ptr_ptr) = EX(original_return_value);
-                       destroy_op_array(op_array TSRMLS_CC);
-                       efree(op_array);
-                       if (UNEXPECTED(EG(exception) != NULL)) {
-                               zend_throw_exception_internal(NULL TSRMLS_CC);
-                               HANDLE_EXCEPTION_LEAVE();
-                       } else if (RETURN_VALUE_USED(opline)) {
-                               if (!EX_T(opline->result.var).var.ptr) { /* there was no return statement */
-                                       zval *retval;
-
-                                       ALLOC_ZVAL(retval);
-                                       ZVAL_BOOL(retval, 1);
-                                       INIT_PZVAL(retval);
-                                       EX_T(opline->result.var).var.ptr = retval;
-                               }
-                       }
-
-                       ZEND_VM_INC_OPCODE();
-                       ZEND_VM_LEAVE();
-               } else {
-
-                       EG(opline_ptr) = &EX(opline);
-                       EG(active_op_array) = EX(op_array);
-                       EG(return_value_ptr_ptr) = EX(original_return_value);
-                       if (EG(active_symbol_table)) {
-                               if (EG(symtable_cache_ptr)>=EG(symtable_cache_limit)) {
-                                       zend_hash_destroy(EG(active_symbol_table));
-                                       FREE_HASHTABLE(EG(active_symbol_table));
-                               } else {
-                                       /* clean before putting into the cache, since clean
-                                          could call dtors, which could use cached hash */
-                                       zend_hash_clean(EG(active_symbol_table));
-                                       *(++EG(symtable_cache_ptr)) = EG(active_symbol_table);
-                               }
-                       }
-                       EG(active_symbol_table) = EX(symbol_table);
-
-                       EX(function_state).function = (zend_function *) EX(op_array);
-                       EX(function_state).arguments = NULL;
-
-                       if (EG(This)) {
-                               if (UNEXPECTED(EG(exception) != NULL) && IS_CTOR_CALL(EX(called_scope))) {
-                                       if (IS_CTOR_USED(EX(called_scope))) {
-                                               Z_DELREF_P(EG(This));
-                                       }
-                                       if (Z_REFCOUNT_P(EG(This)) == 1) {
-                                               zend_object_store_ctor_failed(EG(This) TSRMLS_CC);
-                                       }
-                               }
-                               zval_ptr_dtor(&EG(This));
-                       }
-                       EG(This) = EX(current_this);
-                       EG(scope) = EX(current_scope);
-                       EG(called_scope) = EX(current_called_scope);
-
-                       EX(object) = EX(current_object);
-                       EX(called_scope) = DECODE_CTOR(EX(called_scope));
-
-                       zend_vm_stack_clear_multiple(TSRMLS_C);
-
-                       if (UNEXPECTED(EG(exception) != NULL)) {
-                               zend_throw_exception_internal(NULL TSRMLS_CC);
-                               if (RETURN_VALUE_USED(opline) && EX_T(opline->result.var).var.ptr) {
-                                       zval_ptr_dtor(&EX_T(opline->result.var).var.ptr);
-                               }
-                               HANDLE_EXCEPTION_LEAVE();
-                       }
-
-                       ZEND_VM_INC_OPCODE();
-                       ZEND_VM_LEAVE();
-               }
-       }
-       ZEND_VM_RETURN();
-}
-
-ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY)
-{
-       USE_OPLINE
-       zend_bool should_change_scope = 0;
-       zend_function *fbc = EX(function_state).function;
-
-       SAVE_OPLINE();
-       if (UNEXPECTED((fbc->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_DEPRECATED)) != 0)) {
-               if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_ABSTRACT) != 0)) {
-                       zend_error_noreturn(E_ERROR, "Cannot call abstract method %s::%s()", fbc->common.scope->name, fbc->common.function_name);
-                       CHECK_EXCEPTION();
-                       ZEND_VM_NEXT_OPCODE(); /* Never reached */
-               }
-               if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) {
-                       zend_error(E_DEPRECATED, "Function %s%s%s() is deprecated",
-                               fbc->common.scope ? fbc->common.scope->name : "",
-                               fbc->common.scope ? "::" : "",
-                               fbc->common.function_name);
-               }
-       }
-       if (fbc->common.scope &&
-               !(fbc->common.fn_flags & ZEND_ACC_STATIC) &&
-               !EX(object)) {
-
-               if (fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) {
-                       /* FIXME: output identifiers properly */
-                       zend_error(E_STRICT, "Non-static method %s::%s() should not be called statically", fbc->common.scope->name, fbc->common.function_name);
-               } else {
-                       /* FIXME: output identifiers properly */
-                       /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */
-                       zend_error_noreturn(E_ERROR, "Non-static method %s::%s() cannot be called statically", fbc->common.scope->name, fbc->common.function_name);
-               }
-       }
-
-       if (fbc->type == ZEND_USER_FUNCTION || fbc->common.scope) {
-               should_change_scope = 1;
-               EX(current_this) = EG(This);
-               EX(current_scope) = EG(scope);
-               EX(current_called_scope) = EG(called_scope);
-               EG(This) = EX(object);
-               EG(scope) = (fbc->type == ZEND_USER_FUNCTION || !EX(object)) ? fbc->common.scope : NULL;
-               EG(called_scope) = EX(called_scope);
-       }
-
-       zend_arg_types_stack_3_pop(&EG(arg_types_stack), &EX(called_scope), &EX(current_object), &EX(fbc));
-       EX(function_state).arguments = zend_vm_stack_push_args(opline->extended_value TSRMLS_CC);
-       LOAD_OPLINE();
-
-       if (fbc->type == ZEND_INTERNAL_FUNCTION) {
-               temp_variable *ret = &EX_T(opline->result.var);
-
-               MAKE_STD_ZVAL(ret->var.ptr);
-               ZVAL_NULL(ret->var.ptr);
-               ret->var.ptr_ptr = &ret->var.ptr;
-               ret->var.fcall_returned_reference = (fbc->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0;
-
-               if (fbc->common.arg_info) {
-                       zend_uint i=0;
-                       zval **p = (zval**)EX(function_state).arguments;
-                       ulong arg_count = opline->extended_value;
-
-                       while (arg_count>0) {
-                               zend_verify_arg_type(fbc, ++i, *(p-arg_count), 0 TSRMLS_CC);
-                               arg_count--;
+                       } else {
+                               FREE_OP2();
                        }
-               }
-
-               if (!zend_execute_internal) {
-                       /* saves one function call if zend_execute_internal is not used */
-                       fbc->internal_function.handler(opline->extended_value, ret->var.ptr, (fbc->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) ? &ret->var.ptr : NULL, EX(object), RETURN_VALUE_USED(opline) TSRMLS_CC);
-               } else {
-                       zend_execute_internal(EXECUTE_DATA, RETURN_VALUE_USED(opline) TSRMLS_CC);
-               }
-
-               if (!RETURN_VALUE_USED(opline)) {
-                       zval_ptr_dtor(&ret->var.ptr);
-               }
-       } else if (fbc->type == ZEND_USER_FUNCTION) {
-               EX(original_return_value) = EG(return_value_ptr_ptr);
-               EG(active_symbol_table) = NULL;
-               EG(active_op_array) = &fbc->op_array;
-               EG(return_value_ptr_ptr) = NULL;
-               if (RETURN_VALUE_USED(opline)) {
-                       temp_variable *ret = &EX_T(opline->result.var);
+                       CHECK_EXCEPTION();
+                       ZEND_VM_NEXT_OPCODE();
+               } else if (OP2_TYPE != IS_CONST &&
+                               EXPECTED(Z_TYPE_P(function_name) == IS_ARRAY) &&
+                               zend_hash_num_elements(Z_ARRVAL_P(function_name)) == 2) {
+                       zend_class_entry *ce;
+                       zval **method = NULL;
+                       zval **obj = NULL;
 
-                       ret->var.ptr = NULL;
-                       EG(return_value_ptr_ptr) = &ret->var.ptr;
-                       ret->var.ptr_ptr = &ret->var.ptr;
-                       ret->var.fcall_returned_reference = (fbc->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0;
-               }
+                       zend_hash_index_find(Z_ARRVAL_P(function_name), 0, (void **) &obj);
+                       zend_hash_index_find(Z_ARRVAL_P(function_name), 1, (void **) &method);
 
-               if (EXPECTED(zend_execute == execute)) {
-                       if (EXPECTED(EG(exception) == NULL)) {
-                               ZEND_VM_ENTER();
+                       if (Z_TYPE_PP(obj) != IS_STRING && Z_TYPE_PP(obj) != IS_OBJECT) {
+                               zend_error_noreturn(E_ERROR, "First array member is not a valid class name or object");
                        }
-               } else {
-                       zend_execute(EG(active_op_array) TSRMLS_CC);
-               }
 
-               EG(opline_ptr) = &EX(opline);
-               EG(active_op_array) = EX(op_array);
-               EG(return_value_ptr_ptr) = EX(original_return_value);
-               if (EG(active_symbol_table)) {
-                       if (EG(symtable_cache_ptr)>=EG(symtable_cache_limit)) {
-                               zend_hash_destroy(EG(active_symbol_table));
-                               FREE_HASHTABLE(EG(active_symbol_table));
-                       } else {
-                               /* clean before putting into the cache, since clean
-                                  could call dtors, which could use cached hash */
-                               zend_hash_clean(EG(active_symbol_table));
-                               *(++EG(symtable_cache_ptr)) = EG(active_symbol_table);
+                       if (Z_TYPE_PP(method) != IS_STRING) {
+                               zend_error_noreturn(E_ERROR, "Second array member is not a valid method");
                        }
-               }
-               EG(active_symbol_table) = EX(symbol_table);
-       } else { /* ZEND_OVERLOADED_FUNCTION */
-               MAKE_STD_ZVAL(EX_T(opline->result.var).var.ptr);
-               ZVAL_NULL(EX_T(opline->result.var).var.ptr);
-
-                       /* Not sure what should be done here if it's a static method */
-               if (EXPECTED(EX(object) != NULL)) {
-                       Z_OBJ_HT_P(EX(object))->call_method(fbc->common.function_name, opline->extended_value, EX_T(opline->result.var).var.ptr, &EX_T(opline->result.var).var.ptr, EX(object), RETURN_VALUE_USED(opline) TSRMLS_CC);
-               } else {
-                       zend_error_noreturn(E_ERROR, "Cannot call overloaded function for non-object");
-               }
-
-               if (fbc->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) {
-                       efree((char*)fbc->common.function_name);
-               }
-               efree(fbc);
 
-               if (!RETURN_VALUE_USED(opline)) {
-                       zval_ptr_dtor(&EX_T(opline->result.var).var.ptr);
-               } else {
-                       Z_UNSET_ISREF_P(EX_T(opline->result.var).var.ptr);
-                       Z_SET_REFCOUNT_P(EX_T(opline->result.var).var.ptr, 1);
-                       EX_T(opline->result.var).var.fcall_returned_reference = 0;
-                       EX_T(opline->result.var).var.ptr_ptr = &EX_T(opline->result.var).var.ptr;
-               }
-       }
+                       if (Z_TYPE_PP(obj) == IS_STRING) {
+                               ce = zend_fetch_class_by_name(Z_STRVAL_PP(obj), Z_STRLEN_PP(obj), NULL, 0 TSRMLS_CC);
+                               if (UNEXPECTED(ce == NULL)) {
+                                       CHECK_EXCEPTION();
+                                       ZEND_VM_NEXT_OPCODE();
+                               }
+                               EX(called_scope) = ce;
+                               EX(object) = NULL;
 
-       EX(function_state).function = (zend_function *) EX(op_array);
-       EX(function_state).arguments = NULL;
+                               if (ce->get_static_method) {
+                                       EX(fbc) = ce->get_static_method(ce, Z_STRVAL_PP(method), Z_STRLEN_PP(method) TSRMLS_CC);
+                               } else {
+                                       EX(fbc) = zend_std_get_static_method(ce, Z_STRVAL_PP(method), Z_STRLEN_PP(method), NULL TSRMLS_CC);
+                               }
+                       } else {
+                               EX(object) = *obj;
+                               ce = EX(called_scope) = Z_OBJCE_PP(obj);
 
-       if (should_change_scope) {
-               if (EG(This)) {
-                       if (UNEXPECTED(EG(exception) != NULL) && IS_CTOR_CALL(EX(called_scope))) {
-                               if (IS_CTOR_USED(EX(called_scope))) {
-                                       Z_DELREF_P(EG(This));
+                               EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), Z_STRVAL_PP(method), Z_STRLEN_PP(method), NULL TSRMLS_CC);
+                               if (UNEXPECTED(EX(fbc) == NULL)) {
+                                       zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), Z_STRVAL_PP(method));
                                }
-                               if (Z_REFCOUNT_P(EG(This)) == 1) {
-                                       zend_object_store_ctor_failed(EG(This) TSRMLS_CC);
+
+                               if ((EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) != 0) {
+                                       EX(object) = NULL;
+                               } else {
+                                       if (!PZVAL_IS_REF(EX(object))) {
+                                               Z_ADDREF_P(EX(object)); /* For $this pointer */
+                                       } else {
+                                               zval *this_ptr;
+                                               ALLOC_ZVAL(this_ptr);
+                                               INIT_PZVAL_COPY(this_ptr, EX(object));
+                                               zval_copy_ctor(this_ptr);
+                                               EX(object) = this_ptr;
+                                       }
                                }
                        }
-                       zval_ptr_dtor(&EG(This));
+
+                       if (UNEXPECTED(EX(fbc) == NULL)) {
+                               zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name, Z_STRVAL_PP(method));
+                       }
+                       FREE_OP2();
+                       CHECK_EXCEPTION();
+                       ZEND_VM_NEXT_OPCODE();
+               } else {
+                       zend_error_noreturn(E_ERROR, "Function name must be a string");
                }
-               EG(This) = EX(current_this);
-               EG(scope) = EX(current_scope);
-               EG(called_scope) = EX(current_called_scope);
        }
+}
 
-       EX(object) = EX(current_object);
-       EX(called_scope) = DECODE_CTOR(EX(called_scope));
 
-       zend_vm_stack_clear_multiple(TSRMLS_C);
+ZEND_VM_HANDLER(69, ZEND_INIT_NS_FCALL_BY_NAME, ANY, CONST)
+{
+       USE_OPLINE
+       zend_literal *func_name;
 
-       if (UNEXPECTED(EG(exception) != NULL)) {
-               zend_throw_exception_internal(NULL TSRMLS_CC);
-               if (RETURN_VALUE_USED(opline) && EX_T(opline->result.var).var.ptr) {
-                       zval_ptr_dtor(&EX_T(opline->result.var).var.ptr);
+       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope));
+
+       func_name = opline->op2.literal + 1;
+       if (CACHED_PTR(opline->op2.literal->cache_slot)) {
+               EX(fbc) = CACHED_PTR(opline->op2.literal->cache_slot);
+       } else if (zend_hash_quick_find(EG(function_table), Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant)+1, func_name->hash_value, (void **) &EX(fbc))==FAILURE) {
+               func_name++;
+               if (UNEXPECTED(zend_hash_quick_find(EG(function_table), Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant)+1, func_name->hash_value, (void **) &EX(fbc))==FAILURE)) {
+                       SAVE_OPLINE();
+                       zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv));
+               } else {
+                       CACHE_PTR(opline->op2.literal->cache_slot, EX(fbc));
                }
-               HANDLE_EXCEPTION();
+       } else {
+               CACHE_PTR(opline->op2.literal->cache_slot, EX(fbc));
        }
 
+       EX(object) = NULL;
        ZEND_VM_NEXT_OPCODE();
 }
 
@@ -2878,10 +2975,10 @@ ZEND_VM_HANDLER(62, ZEND_RETURN, CONST|TMP|VAR|CV, ANY)
        }
        FREE_OP1_IF_VAR();
 
-    if (EG(active_op_array)->has_finally_block) {
-        ZEND_VM_DISPATCH_TO_HELPER_EX(zend_finally_handler_leaving, type, ZEND_RETURN);
-    }
-    ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper);
+       if (EX(op_array)->has_finally_block) {
+               ZEND_VM_DISPATCH_TO_HELPER_EX(zend_finally_handler_leaving, type, ZEND_RETURN);
+       }
+       ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper);
 }
 
 ZEND_VM_HANDLER(111, ZEND_RETURN_BY_REF, CONST|TMP|VAR|CV, ANY)
@@ -2954,10 +3051,10 @@ ZEND_VM_HANDLER(111, ZEND_RETURN_BY_REF, CONST|TMP|VAR|CV, ANY)
 
        FREE_OP1_IF_VAR();
 
-    if (EG(active_op_array)->has_finally_block) {
-        ZEND_VM_DISPATCH_TO_HELPER_EX(zend_finally_handler_leaving, type, ZEND_RETURN_BY_REF);
-    }
-    ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper);
+       if (EX(op_array)->has_finally_block) {
+               ZEND_VM_DISPATCH_TO_HELPER_EX(zend_finally_handler_leaving, type, ZEND_RETURN_BY_REF);
+       }
+       ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper);
 }
 
 ZEND_VM_HANDLER(108, ZEND_THROW, CONST|TMP|VAR|CV, ANY)
@@ -3292,93 +3389,6 @@ ZEND_VM_HANDLER(52, ZEND_BOOL, CONST|TMP|VAR|CV, ANY)
        ZEND_VM_NEXT_OPCODE();
 }
 
-ZEND_VM_HELPER_EX(zend_finally_handler_leaving, ANY, ANY, int type)
-{
-       USE_OPLINE
-       zend_uint i, op_num = opline - EX(op_array)->opcodes;
-       zend_uint catch_op_num = 0, finally_op_num = 0;
-
-       SAVE_OPLINE();
-
-       switch (type) {
-               case ZEND_THROW:
-               case ZEND_RETURN:
-               case ZEND_RETURN_BY_REF:
-                       {
-                               if (EG(prev_exception)) {
-                                       for (i=0; i<EG(active_op_array)->last_try_catch; i++) {
-                                               if (EG(active_op_array)->try_catch_array[i].try_op > op_num) {
-                                                       break;
-                                               } 
-                                               if (op_num < EG(active_op_array)->try_catch_array[i].finally_op) {
-                                                       finally_op_num = EG(active_op_array)->try_catch_array[i].finally_op;
-                                               }
-                                               if (op_num < EG(active_op_array)->try_catch_array[i].catch_op) {
-                                                       catch_op_num = EG(active_op_array)->try_catch_array[i].catch_op;
-                                               }
-                                       }
-                               } else {
-                                       for (i=0; i<EG(active_op_array)->last_try_catch; i++) {
-                                               if (EG(active_op_array)->try_catch_array[i].try_op > op_num) {
-                                                       break;
-                                               } 
-                                               if (op_num < EG(active_op_array)->try_catch_array[i].finally_op) {
-                                                       finally_op_num = EG(active_op_array)->try_catch_array[i].finally_op;
-                                               }
-                                       }
-                               }
-
-                               if (catch_op_num && finally_op_num) {
-                                       /* EG(exception) || EG(prev_exception) */
-                                       if (catch_op_num > finally_op_num) {
-                                               EX(leaving) = ZEND_THROW;
-                                               ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[finally_op_num]);
-                                       } else {
-                                               EX(leaving) = 0;
-                                               ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[catch_op_num]);
-                                       }
-                               } else if (catch_op_num) {
-                                       EX(leaving) = 0;
-                                       ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[catch_op_num]);
-                               } else if (finally_op_num) {
-                                       EX(leaving) = type;
-                                       ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[finally_op_num]);
-                               } else if (EX(leaving)) {
-                                       /* leave it to ZEND_LEAVE */
-                                       ZEND_VM_NEXT_OPCODE();
-                               } else {
-                                       ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper);
-                               }
-                       }
-                       break;
-               case ZEND_BRK:
-               case ZEND_CONT:
-               case ZEND_GOTO:
-                       {
-                               for (i=0; i<EG(active_op_array)->last_try_catch; i++) {
-                                       if (EG(active_op_array)->try_catch_array[i].try_op > op_num) {
-                                               break;
-                                       } 
-                                       if (op_num < EG(active_op_array)->try_catch_array[i].finally_op 
-                                                       && (EX(leaving_dest) < EG(active_op_array)->try_catch_array[i].try_op
-                                || EX(leaving_dest) >= EG(active_op_array)->try_catch_array[i].finally_end)) {
-                                               finally_op_num = EG(active_op_array)->try_catch_array[i].finally_op;
-                                       }
-                               }
-
-                               if (finally_op_num) {
-                                       EX(leaving) = type;
-                                       ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[finally_op_num]);
-                               } else {
-                    EX(leaving) = 0;
-                                       ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[EX(leaving_dest)]);
-                               }
-                       }
-                       break;
-       }
-       ZEND_VM_CONTINUE();
-}
-
 ZEND_VM_HANDLER(50, ZEND_BRK, ANY, CONST)
 {
        USE_OPLINE
@@ -3388,10 +3398,10 @@ ZEND_VM_HANDLER(50, ZEND_BRK, ANY, CONST)
        el = zend_brk_cont(Z_LVAL_P(opline->op2.zv), opline->op1.opline_num,
                           EX(op_array), EX_Ts() TSRMLS_CC);
        FREE_OP2();
-    if (EG(active_op_array)->has_finally_block) {
-        EX(leaving_dest) = el->brk;
-        ZEND_VM_DISPATCH_TO_HELPER_EX(zend_finally_handler_leaving, type, ZEND_BRK);
-    }
+       if (EX(op_array)->has_finally_block) {
+               EX(leaving_dest) = el->brk;
+               ZEND_VM_DISPATCH_TO_HELPER_EX(zend_finally_handler_leaving, type, ZEND_BRK);
+       }
        ZEND_VM_JMP(EX(op_array)->opcodes + el->brk);
 }
 
@@ -3404,10 +3414,10 @@ ZEND_VM_HANDLER(51, ZEND_CONT, ANY, CONST)
        el = zend_brk_cont(Z_LVAL_P(opline->op2.zv), opline->op1.opline_num,
                           EX(op_array), EX_Ts() TSRMLS_CC);
        FREE_OP2();
-    if (EG(active_op_array)->has_finally_block) {
-        EX(leaving_dest) = el->cont;
-        ZEND_VM_DISPATCH_TO_HELPER_EX(zend_finally_handler_leaving, type, ZEND_CONT);
-    }
+       if (EG(active_op_array)->has_finally_block) {
+               EX(leaving_dest) = el->cont;
+               ZEND_VM_DISPATCH_TO_HELPER_EX(zend_finally_handler_leaving, type, ZEND_CONT);
+       }
        ZEND_VM_JMP(EX(op_array)->opcodes + el->cont);
 }
 
@@ -3435,10 +3445,10 @@ ZEND_VM_HANDLER(100, ZEND_GOTO, ANY, CONST)
                        }
                        break;
        }
-    if ((EG(active_op_array)->has_finally_block)) {
-        EX(leaving_dest) = opline->op1.jmp_addr - EG(active_op_array)->opcodes;
-        ZEND_VM_DISPATCH_TO_HELPER_EX(zend_finally_handler_leaving, type, ZEND_GOTO);
-    }
+       if (EX(op_array)->has_finally_block) {
+               EX(leaving_dest) = opline->op1.jmp_addr - EX(op_array)->opcodes;
+               ZEND_VM_DISPATCH_TO_HELPER_EX(zend_finally_handler_leaving, type, ZEND_GOTO);
+       }
        ZEND_VM_JMP(opline->op1.jmp_addr);
 }
 
@@ -5305,7 +5315,7 @@ ZEND_VM_HANDLER(153, ZEND_DECLARE_LAMBDA_FUNCTION, CONST, UNUSED)
        zend_function *op_array;
 
        SAVE_OPLINE();
-            
+
        if (UNEXPECTED(zend_hash_quick_find(EG(function_table), Z_STRVAL_P(opline->op1.zv), Z_STRLEN_P(opline->op1.zv), Z_HASH_P(opline->op1.zv), (void *) &op_array) == FAILURE) ||
            UNEXPECTED(op_array->type != ZEND_USER_FUNCTION)) {
                zend_error_noreturn(E_ERROR, "Base lambda function for closure not found");
@@ -5340,64 +5350,21 @@ ZEND_VM_HANDLER(156, ZEND_SEPARATE, VAR, UNUSED)
 
 ZEND_VM_HANDLER(159, ZEND_LEAVE, ANY, ANY)
 {
-       USE_OPLINE
        zend_exception_restore(TSRMLS_C);
-
        if (!EX(leaving)) {
                ZEND_VM_NEXT_OPCODE();
        } else {
-               zend_uint i, op_num = opline - EX(op_array)->opcodes;
-               zend_uint catch_op_num = 0, finally_op_num = 0;
-               switch (EX(leaving)) {
+               zend_uint leaving = EX(leaving);
+               switch (leaving) {
                        case ZEND_RETURN:
                        case ZEND_RETURN_BY_REF:
                        case ZEND_THROW:
-                               {
-                                       if (EG(exception)) {
-                                               for (i = 0; i < EX(leaving); i++) {
-                                                       if (EG(active_op_array)->try_catch_array[i].try_op > op_num) {
-                                                               break;
-                                                       } 
-                                                       if (op_num < EG(active_op_array)->try_catch_array[i].finally_op) {
-                                                               finally_op_num = EG(active_op_array)->try_catch_array[i].finally_op;
-                                                       }
-                                                       if (op_num < EG(active_op_array)->try_catch_array[i].catch_op) {
-                                                               catch_op_num = EG(active_op_array)->try_catch_array[i].catch_op;
-                                                       }
-                                               }
-                                       } else {
-                                               for (i = 0; i < EX(leaving); i++) {
-                                                       if (EG(active_op_array)->try_catch_array[i].try_op > op_num) {
-                                                               break;
-                                                       } 
-                                                       if (op_num < EG(active_op_array)->try_catch_array[i].finally_op) {
-                                                               finally_op_num = EG(active_op_array)->try_catch_array[i].finally_op;
-                                                       }
-                                               }
-                                       }
-
-                                       if (catch_op_num && finally_op_num) {
-                                               if (catch_op_num > finally_op_num) {
-                                                       EX(leaving) = ZEND_THROW;
-                                                       ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[finally_op_num]);
-                                               } else {
-                                                       EX(leaving) = 0;
-                                                       ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[catch_op_num]);
-                                               }
-                                       } else if (catch_op_num) {
-                                               EX(leaving) = 0;
-                                               ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[catch_op_num]);
-                                       } else if (finally_op_num) {
-                                               ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[finally_op_num]);
-                                       } else {
-                                               ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper);
-                                       }
-                               }
-                               break;
+                               leaving = ZEND_LEAVE;
+                       case ZEND_JMP:
                        case ZEND_BRK:
                        case ZEND_CONT:
                        case ZEND_GOTO:
-                                ZEND_VM_DISPATCH_TO_HELPER_EX(zend_finally_handler_leaving, type, EX(leaving));
+                                ZEND_VM_DISPATCH_TO_HELPER_EX(zend_finally_handler_leaving, type, leaving);
                        break;
                }
        }
index 9818583334c6ecfbc8f9f52b3fba9e9e410560b2..bd19124574131013dde09c80f8edb6b3d85f9b75 100644 (file)
@@ -427,33 +427,6 @@ zend_vm_enter:
        zend_error_noreturn(E_ERROR, "Arrived at end of main loop which shouldn't happen");
 }
 
-static int ZEND_FASTCALL  ZEND_JMP_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
-{
-       USE_OPLINE
-
-#if DEBUG_ZEND>=2
-       printf("Jumping to %d\n", opline->op1.opline_num);
-#endif
-       ZEND_VM_SET_OPCODE(opline->op1.jmp_addr);
-       ZEND_VM_CONTINUE(); /* CHECK_ME */
-}
-
-static int ZEND_FASTCALL  ZEND_INIT_STRING_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
-{
-       USE_OPLINE
-       zval *tmp = &EX_T(opline->result.var).tmp_var;
-
-       SAVE_OPLINE();
-       tmp->value.str.val = emalloc(1);
-       tmp->value.str.val[0] = 0;
-       tmp->value.str.len = 0;
-       Z_SET_REFCOUNT_P(tmp, 1);
-       tmp->type = IS_STRING;
-       Z_UNSET_ISREF_P(tmp);
-       /*CHECK_EXCEPTION();*/
-       ZEND_VM_NEXT_OPCODE();
-}
-
 static int ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS)
 {
        zend_bool nested;
@@ -747,53 +720,6 @@ static int ZEND_FASTCALL zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_AR
        ZEND_VM_NEXT_OPCODE();
 }
 
-static int ZEND_FASTCALL  ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
-{
-       EX(function_state).function = EX(fbc);
-       return zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
-}
-
-static int ZEND_FASTCALL  ZEND_RECV_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
-{
-       USE_OPLINE
-       zend_uint arg_num = opline->op1.num;
-       zval **param = zend_vm_stack_get_arg(arg_num TSRMLS_CC);
-
-       SAVE_OPLINE();
-       if (UNEXPECTED(param == NULL)) {
-               if (zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, NULL, opline->extended_value TSRMLS_CC)) {
-                       const char *space;
-                       const char *class_name;
-                       zend_execute_data *ptr;
-
-                       if (EG(active_op_array)->scope) {
-                               class_name = EG(active_op_array)->scope->name;
-                               space = "::";
-                       } else {
-                               class_name = space = "";
-                       }
-                       ptr = EX(prev_execute_data);
-
-                       if(ptr && ptr->op_array) {
-                               zend_error(E_WARNING, "Missing argument %u for %s%s%s(), called in %s on line %d and defined", opline->op1.num, class_name, space, get_active_function_name(TSRMLS_C), ptr->op_array->filename, ptr->opline->lineno);
-                       } else {
-                               zend_error(E_WARNING, "Missing argument %u for %s%s%s()", opline->op1.num, class_name, space, get_active_function_name(TSRMLS_C));
-                       }
-               }
-       } else {
-               zval **var_ptr;
-
-               zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, *param, opline->extended_value TSRMLS_CC);
-               var_ptr = _get_zval_ptr_ptr_cv_BP_VAR_W(EX_CVs(), opline->result.var TSRMLS_CC);
-               Z_DELREF_PP(var_ptr);
-               *var_ptr = *param;
-               Z_ADDREF_PP(var_ptr);
-       }
-
-       CHECK_EXCEPTION();
-       ZEND_VM_NEXT_OPCODE();
-}
-
 static int ZEND_FASTCALL zend_finally_handler_leaving_SPEC(int type, ZEND_OPCODE_HANDLER_ARGS)
 {
        USE_OPLINE
@@ -806,26 +732,27 @@ static int ZEND_FASTCALL zend_finally_handler_leaving_SPEC(int type, ZEND_OPCODE
                case ZEND_THROW:
                case ZEND_RETURN:
                case ZEND_RETURN_BY_REF:
+               case ZEND_LEAVE:
                        {
-                               if (EG(prev_exception)) {
-                                       for (i=0; i<EG(active_op_array)->last_try_catch; i++) {
-                                               if (EG(active_op_array)->try_catch_array[i].try_op > op_num) {
+                               if (EG(prev_exception) || (type == ZEND_LEAVE && EG(exception))) {
+                                       for (i=0; i<EX(op_array)->last_try_catch; i++) {
+                                               if (EX(op_array)->try_catch_array[i].try_op > op_num) {
                                                        break;
                                                }
-                                               if (op_num < EG(active_op_array)->try_catch_array[i].finally_op) {
-                                                       finally_op_num = EG(active_op_array)->try_catch_array[i].finally_op;
+                                               if (op_num < EX(op_array)->try_catch_array[i].finally_op) {
+                                                       finally_op_num = EX(op_array)->try_catch_array[i].finally_op;
                                                }
-                                               if (op_num < EG(active_op_array)->try_catch_array[i].catch_op) {
-                                                       catch_op_num = EG(active_op_array)->try_catch_array[i].catch_op;
+                                               if (op_num < EX(op_array)->try_catch_array[i].catch_op) {
+                                                       catch_op_num = EX(op_array)->try_catch_array[i].catch_op;
                                                }
                                        }
                                } else {
-                                       for (i=0; i<EG(active_op_array)->last_try_catch; i++) {
-                                               if (EG(active_op_array)->try_catch_array[i].try_op > op_num) {
+                                       for (i=0; i<EX(op_array)->last_try_catch; i++) {
+                                               if (EX(op_array)->try_catch_array[i].try_op > op_num) {
                                                        break;
                                                }
-                                               if (op_num < EG(active_op_array)->try_catch_array[i].finally_op) {
-                                                       finally_op_num = EG(active_op_array)->try_catch_array[i].finally_op;
+                                               if (op_num < EX(op_array)->try_catch_array[i].finally_op) {
+                                                       finally_op_num = EX(op_array)->try_catch_array[i].finally_op;
                                                }
                                        }
                                }
@@ -843,44 +770,127 @@ static int ZEND_FASTCALL zend_finally_handler_leaving_SPEC(int type, ZEND_OPCODE
                                        EX(leaving) = 0;
                                        ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[catch_op_num]);
                                } else if (finally_op_num) {
-                                       EX(leaving) = type;
+                                       if (type != ZEND_LEAVE) {
+                                               EX(leaving) = type;
+                                       }
                                        ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[finally_op_num]);
-                               } else if (EX(leaving)) {
+                               } else if (EX(leaving) && type != ZEND_LEAVE) {
                                        /* leave it to ZEND_LEAVE */
+                                       EX(leaving) = type;
                                        ZEND_VM_NEXT_OPCODE();
                                } else {
                                        return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
                                }
                        }
                        break;
+               case ZEND_JMP:
                case ZEND_BRK:
                case ZEND_CONT:
                case ZEND_GOTO:
                        {
-                               for (i=0; i<EG(active_op_array)->last_try_catch; i++) {
-                                       if (EG(active_op_array)->try_catch_array[i].try_op > op_num) {
-                                               break;
-                                       }
-                                       if (op_num < EG(active_op_array)->try_catch_array[i].finally_op
-                                                       && (EX(leaving_dest) < EG(active_op_array)->try_catch_array[i].try_op
-                                || EX(leaving_dest) >= EG(active_op_array)->try_catch_array[i].finally_end)) {
-                                               finally_op_num = EG(active_op_array)->try_catch_array[i].finally_op;
-                                       }
-                               }
-
-                               if (finally_op_num) {
-                                       EX(leaving) = type;
-                                       ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[finally_op_num]);
-                               } else {
-                    EX(leaving) = 0;
-                                       ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[EX(leaving_dest)]);
-                               }
-                       }
+                 /* these can not occurred in exception context */
+                 for (i=0; i<EG(active_op_array)->last_try_catch; i++) {
+                         if (EG(active_op_array)->try_catch_array[i].try_op > op_num) {
+                                 break;
+                         }
+                         if (op_num < EG(active_op_array)->try_catch_array[i].finally_op
+                                         && (EX(leaving_dest) < EG(active_op_array)->try_catch_array[i].try_op
+                                                 || EX(leaving_dest) >= EG(active_op_array)->try_catch_array[i].finally_end)) {
+                                 finally_op_num = EG(active_op_array)->try_catch_array[i].finally_op;
+                         }
+                 }
+
+                 if (finally_op_num) {
+                         EX(leaving) = type;
+                         ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[finally_op_num]);
+                 } else {
+                         EX(leaving) = 0;
+                         ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[EX(leaving_dest)]);
+                 }
+         }
                        break;
        }
        ZEND_VM_CONTINUE();
 }
 
+static int ZEND_FASTCALL  ZEND_JMP_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+{
+       USE_OPLINE
+
+#if DEBUG_ZEND>=2
+       printf("Jumping to %d\n", opline->op1.opline_num);
+#endif
+       if (EX(op_array)->has_finally_block) {
+               EX(leaving_dest) = opline->op1.jmp_addr - EX(op_array)->opcodes;
+               return zend_finally_handler_leaving_SPEC(ZEND_JMP, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
+       }
+       ZEND_VM_SET_OPCODE(opline->op1.jmp_addr);
+       ZEND_VM_CONTINUE(); /* CHECK_ME */
+}
+
+static int ZEND_FASTCALL  ZEND_INIT_STRING_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+{
+       USE_OPLINE
+       zval *tmp = &EX_T(opline->result.var).tmp_var;
+
+       SAVE_OPLINE();
+       tmp->value.str.val = emalloc(1);
+       tmp->value.str.val[0] = 0;
+       tmp->value.str.len = 0;
+       Z_SET_REFCOUNT_P(tmp, 1);
+       tmp->type = IS_STRING;
+       Z_UNSET_ISREF_P(tmp);
+       /*CHECK_EXCEPTION();*/
+       ZEND_VM_NEXT_OPCODE();
+}
+
+static int ZEND_FASTCALL  ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+{
+       EX(function_state).function = EX(fbc);
+       return zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
+}
+
+static int ZEND_FASTCALL  ZEND_RECV_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+{
+       USE_OPLINE
+       zend_uint arg_num = opline->op1.num;
+       zval **param = zend_vm_stack_get_arg(arg_num TSRMLS_CC);
+
+       SAVE_OPLINE();
+       if (UNEXPECTED(param == NULL)) {
+               if (zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, NULL, opline->extended_value TSRMLS_CC)) {
+                       const char *space;
+                       const char *class_name;
+                       zend_execute_data *ptr;
+
+                       if (EG(active_op_array)->scope) {
+                               class_name = EG(active_op_array)->scope->name;
+                               space = "::";
+                       } else {
+                               class_name = space = "";
+                       }
+                       ptr = EX(prev_execute_data);
+
+                       if(ptr && ptr->op_array) {
+                               zend_error(E_WARNING, "Missing argument %u for %s%s%s(), called in %s on line %d and defined", opline->op1.num, class_name, space, get_active_function_name(TSRMLS_C), ptr->op_array->filename, ptr->opline->lineno);
+                       } else {
+                               zend_error(E_WARNING, "Missing argument %u for %s%s%s()", opline->op1.num, class_name, space, get_active_function_name(TSRMLS_C));
+                       }
+               }
+       } else {
+               zval **var_ptr;
+
+               zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, *param, opline->extended_value TSRMLS_CC);
+               var_ptr = _get_zval_ptr_ptr_cv_BP_VAR_W(EX_CVs(), opline->result.var TSRMLS_CC);
+               Z_DELREF_PP(var_ptr);
+               *var_ptr = *param;
+               Z_ADDREF_PP(var_ptr);
+       }
+
+       CHECK_EXCEPTION();
+       ZEND_VM_NEXT_OPCODE();
+}
+
 static int ZEND_FASTCALL  ZEND_NEW_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
 {
        USE_OPLINE
@@ -1264,64 +1274,21 @@ static int ZEND_FASTCALL  ZEND_USER_OPCODE_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS
 
 static int ZEND_FASTCALL  ZEND_LEAVE_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
 {
-       USE_OPLINE
        zend_exception_restore(TSRMLS_C);
-
        if (!EX(leaving)) {
                ZEND_VM_NEXT_OPCODE();
        } else {
-               zend_uint i, op_num = opline - EX(op_array)->opcodes;
-               zend_uint catch_op_num = 0, finally_op_num = 0;
-               switch (EX(leaving)) {
+               zend_uint leaving = EX(leaving);
+               switch (leaving) {
                        case ZEND_RETURN:
                        case ZEND_RETURN_BY_REF:
                        case ZEND_THROW:
-                               {
-                                       if (EG(exception)) {
-                                               for (i = 0; i < EX(leaving); i++) {
-                                                       if (EG(active_op_array)->try_catch_array[i].try_op > op_num) {
-                                                               break;
-                                                       }
-                                                       if (op_num < EG(active_op_array)->try_catch_array[i].finally_op) {
-                                                               finally_op_num = EG(active_op_array)->try_catch_array[i].finally_op;
-                                                       }
-                                                       if (op_num < EG(active_op_array)->try_catch_array[i].catch_op) {
-                                                               catch_op_num = EG(active_op_array)->try_catch_array[i].catch_op;
-                                                       }
-                                               }
-                                       } else {
-                                               for (i = 0; i < EX(leaving); i++) {
-                                                       if (EG(active_op_array)->try_catch_array[i].try_op > op_num) {
-                                                               break;
-                                                       }
-                                                       if (op_num < EG(active_op_array)->try_catch_array[i].finally_op) {
-                                                               finally_op_num = EG(active_op_array)->try_catch_array[i].finally_op;
-                                                       }
-                                               }
-                                       }
-
-                                       if (catch_op_num && finally_op_num) {
-                                               if (catch_op_num > finally_op_num) {
-                                                       EX(leaving) = ZEND_THROW;
-                                                       ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[finally_op_num]);
-                                               } else {
-                                                       EX(leaving) = 0;
-                                                       ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[catch_op_num]);
-                                               }
-                                       } else if (catch_op_num) {
-                                               EX(leaving) = 0;
-                                               ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[catch_op_num]);
-                                       } else if (finally_op_num) {
-                                               ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[finally_op_num]);
-                                       } else {
-                                               return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
-                                       }
-                               }
-                               break;
+                               leaving = ZEND_LEAVE;
+                       case ZEND_JMP:
                        case ZEND_BRK:
                        case ZEND_CONT:
                        case ZEND_GOTO:
-                                return zend_finally_handler_leaving_SPEC(EX(leaving), ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
+                                return zend_finally_handler_leaving_SPEC(leaving, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
                        break;
                }
        }
@@ -1563,10 +1530,10 @@ static int ZEND_FASTCALL  ZEND_BRK_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
        el = zend_brk_cont(Z_LVAL_P(opline->op2.zv), opline->op1.opline_num,
                           EX(op_array), EX_Ts() TSRMLS_CC);
 
-    if (EG(active_op_array)->has_finally_block) {
-        EX(leaving_dest) = el->brk;
-        return zend_finally_handler_leaving_SPEC(ZEND_BRK, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
-    }
+       if (EX(op_array)->has_finally_block) {
+               EX(leaving_dest) = el->brk;
+               return zend_finally_handler_leaving_SPEC(ZEND_BRK, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
+       }
        ZEND_VM_JMP(EX(op_array)->opcodes + el->brk);
 }
 
@@ -1579,10 +1546,10 @@ static int ZEND_FASTCALL  ZEND_CONT_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
        el = zend_brk_cont(Z_LVAL_P(opline->op2.zv), opline->op1.opline_num,
                           EX(op_array), EX_Ts() TSRMLS_CC);
 
-    if (EG(active_op_array)->has_finally_block) {
-        EX(leaving_dest) = el->cont;
-        return zend_finally_handler_leaving_SPEC(ZEND_CONT, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
-    }
+       if (EG(active_op_array)->has_finally_block) {
+               EX(leaving_dest) = el->cont;
+               return zend_finally_handler_leaving_SPEC(ZEND_CONT, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
+       }
        ZEND_VM_JMP(EX(op_array)->opcodes + el->cont);
 }
 
@@ -1610,10 +1577,10 @@ static int ZEND_FASTCALL  ZEND_GOTO_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
                        }
                        break;
        }
-    if ((EG(active_op_array)->has_finally_block)) {
-        EX(leaving_dest) = opline->op1.jmp_addr - EG(active_op_array)->opcodes;
-        return zend_finally_handler_leaving_SPEC(ZEND_CONT, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
-    }
+       if (EX(op_array)->has_finally_block) {
+               EX(leaving_dest) = opline->op1.jmp_addr - EX(op_array)->opcodes;
+               return zend_finally_handler_leaving_SPEC(ZEND_GOTO, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
+       }
        ZEND_VM_JMP(opline->op1.jmp_addr);
 }
 
@@ -2465,10 +2432,10 @@ static int ZEND_FASTCALL  ZEND_RETURN_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARG
                *EG(return_value_ptr_ptr) = ret;
        }
 
-    if (EG(active_op_array)->has_finally_block) {
-        return zend_finally_handler_leaving_SPEC(ZEND_RETURN, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
-    }
-    return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
+       if (EX(op_array)->has_finally_block) {
+               return zend_finally_handler_leaving_SPEC(ZEND_RETURN, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
+       }
+       return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
 }
 
 static int ZEND_FASTCALL  ZEND_RETURN_BY_REF_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
@@ -2539,10 +2506,10 @@ static int ZEND_FASTCALL  ZEND_RETURN_BY_REF_SPEC_CONST_HANDLER(ZEND_OPCODE_HAND
                }
        } while (0);
 
-    if (EG(active_op_array)->has_finally_block) {
-        return zend_finally_handler_leaving_SPEC(ZEND_RETURN_BY_REF, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
-    }
-    return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
+       if (EX(op_array)->has_finally_block) {
+               return zend_finally_handler_leaving_SPEC(ZEND_RETURN_BY_REF, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
+       }
+       return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
 }
 
 static int ZEND_FASTCALL  ZEND_THROW_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
@@ -7015,10 +6982,10 @@ static int ZEND_FASTCALL  ZEND_RETURN_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
                *EG(return_value_ptr_ptr) = ret;
        }
 
-    if (EG(active_op_array)->has_finally_block) {
-        return zend_finally_handler_leaving_SPEC(ZEND_RETURN, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
-    }
-    return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
+       if (EX(op_array)->has_finally_block) {
+               return zend_finally_handler_leaving_SPEC(ZEND_RETURN, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
+       }
+       return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
 }
 
 static int ZEND_FASTCALL  ZEND_RETURN_BY_REF_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
@@ -7089,10 +7056,10 @@ static int ZEND_FASTCALL  ZEND_RETURN_BY_REF_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLE
                }
        } while (0);
 
-    if (EG(active_op_array)->has_finally_block) {
-        return zend_finally_handler_leaving_SPEC(ZEND_RETURN_BY_REF, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
-    }
-    return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
+       if (EX(op_array)->has_finally_block) {
+               return zend_finally_handler_leaving_SPEC(ZEND_RETURN_BY_REF, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
+       }
+       return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
 }
 
 static int ZEND_FASTCALL  ZEND_THROW_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
@@ -11471,10 +11438,10 @@ static int ZEND_FASTCALL  ZEND_RETURN_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
        }
        if (free_op1.var) {zval_ptr_dtor(&free_op1.var);};
 
-    if (EG(active_op_array)->has_finally_block) {
-        return zend_finally_handler_leaving_SPEC(ZEND_RETURN, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
-    }
-    return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
+       if (EX(op_array)->has_finally_block) {
+               return zend_finally_handler_leaving_SPEC(ZEND_RETURN, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
+       }
+       return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
 }
 
 static int ZEND_FASTCALL  ZEND_RETURN_BY_REF_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
@@ -11547,10 +11514,10 @@ static int ZEND_FASTCALL  ZEND_RETURN_BY_REF_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLE
 
        if (free_op1.var) {zval_ptr_dtor(&free_op1.var);};
 
-    if (EG(active_op_array)->has_finally_block) {
-        return zend_finally_handler_leaving_SPEC(ZEND_RETURN_BY_REF, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
-    }
-    return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
+       if (EX(op_array)->has_finally_block) {
+               return zend_finally_handler_leaving_SPEC(ZEND_RETURN_BY_REF, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
+       }
+       return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
 }
 
 static int ZEND_FASTCALL  ZEND_THROW_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
@@ -27490,10 +27457,10 @@ static int ZEND_FASTCALL  ZEND_RETURN_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
                *EG(return_value_ptr_ptr) = ret;
        }
 
-    if (EG(active_op_array)->has_finally_block) {
-        return zend_finally_handler_leaving_SPEC(ZEND_RETURN, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
-    }
-    return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
+       if (EX(op_array)->has_finally_block) {
+               return zend_finally_handler_leaving_SPEC(ZEND_RETURN, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
+       }
+       return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
 }
 
 static int ZEND_FASTCALL  ZEND_RETURN_BY_REF_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
@@ -27564,10 +27531,10 @@ static int ZEND_FASTCALL  ZEND_RETURN_BY_REF_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER
                }
        } while (0);
 
-    if (EG(active_op_array)->has_finally_block) {
-        return zend_finally_handler_leaving_SPEC(ZEND_RETURN_BY_REF, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
-    }
-    return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
+       if (EX(op_array)->has_finally_block) {
+               return zend_finally_handler_leaving_SPEC(ZEND_RETURN_BY_REF, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
+       }
+       return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
 }
 
 static int ZEND_FASTCALL  ZEND_THROW_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)