]> granicus.if.org Git - php/commitdiff
Merge branch 'PHP-5.6'
authorDmitry Stogov <dmitry@zend.com>
Tue, 25 Nov 2014 15:12:30 +0000 (18:12 +0300)
committerDmitry Stogov <dmitry@zend.com>
Tue, 25 Nov 2014 15:12:30 +0000 (18:12 +0300)
* PHP-5.6:
  Better fix for bug #68446

1  2 
Zend/zend_compile.c
Zend/zend_execute.c
Zend/zend_vm_def.h
Zend/zend_vm_execute.h

index d15b85fc0ba28dec863fa8d4d22b1b5f4d9c2dd1,ccaf1652c256a850f53a03d90b1afd463ac93daf..6caa294448111e4d3ce46a4aab2694fd4daabd96
@@@ -3749,160 -5068,141 +3749,160 @@@ void zend_compile_stmt_list(zend_ast *a
  }
  /* }}} */
  
 -void zend_do_default_before_statement(const znode *case_list, znode *default_token TSRMLS_DC) /* {{{ */
 +void zend_compile_params(zend_ast *ast TSRMLS_DC) /* {{{ */
  {
 -      int next_op_number = get_next_op_number(CG(active_op_array));
 -      zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
 -      zend_switch_entry *switch_entry_ptr;
 +      zend_ast_list *list = zend_ast_get_list(ast);
 +      uint32_t i;
 +      zend_op_array *op_array = CG(active_op_array);
 +      zend_arg_info *arg_infos;
  
 -      zend_stack_top(&CG(switch_cond_stack), (void **) &switch_entry_ptr);
 +      if (list->children == 0) {
 +              return;
 +      }
 +      
 +      arg_infos = safe_emalloc(sizeof(zend_arg_info), list->children, 0);
 +      for (i = 0; i < list->children; ++i) {
 +              zend_ast *param_ast = list->child[i];
 +              zend_ast *type_ast = param_ast->child[0];
 +              zend_ast *var_ast = param_ast->child[1];
 +              zend_ast *default_ast = param_ast->child[2];
 +              zend_string *name = zend_ast_get_str(var_ast);
 +              zend_bool is_ref = (param_ast->attr & ZEND_PARAM_REF) != 0;
 +              zend_bool is_variadic = (param_ast->attr & ZEND_PARAM_VARIADIC) != 0;
 +
 +              znode var_node, default_node;
 +              zend_uchar opcode;
 +              zend_op *opline;
 +              zend_arg_info *arg_info;
  
 -      opline->opcode = ZEND_JMP;
 -      SET_UNUSED(opline->op1);
 -      SET_UNUSED(opline->op2);
 -      default_token->u.op.opline_num = next_op_number;
 +              if (zend_is_auto_global(name TSRMLS_CC)) {
 +                      zend_error_noreturn(E_COMPILE_ERROR, "Cannot re-assign auto-global variable %s",
 +                              name->val);
 +              }
  
 -      next_op_number = get_next_op_number(CG(active_op_array));
 -      switch_entry_ptr->default_case = next_op_number;
 +              var_node.op_type = IS_CV;
 +              var_node.u.op.var = lookup_cv(CG(active_op_array), zend_string_copy(name) TSRMLS_CC);
  
 -      if (case_list->op_type==IS_UNUSED) {
 -              return;
 -      }
 -      CG(active_op_array)->opcodes[case_list->u.op.opline_num].op1.opline_num = next_op_number;
 -}
 -/* }}} */
 -
 -void zend_do_begin_class_declaration(const znode *class_token, znode *class_name, const znode *parent_class_name TSRMLS_DC) /* {{{ */
 -{
 -      zend_op *opline;
 -      int doing_inheritance = 0;
 -      zend_class_entry *new_class_entry;
 -      char *lcname;
 -      int error = 0;
 -      zval **ns_name, key;
 -
 -      if (CG(active_class_entry)) {
 -              zend_error_noreturn(E_COMPILE_ERROR, "Class declarations may not be nested");
 -              return;
 -      }
 +              if (EX_VAR_TO_NUM(var_node.u.op.var) != i) {
 +                      zend_error_noreturn(E_COMPILE_ERROR, "Redefinition of parameter $%s",
 +                              name->val);
 +              } else if (zend_string_equals_literal(name, "this")) {
 +                      if (op_array->scope && (op_array->fn_flags & ZEND_ACC_STATIC) == 0) {
 +                              zend_error_noreturn(E_COMPILE_ERROR, "Cannot re-assign $this");
 +                      }
 +                      op_array->this_var = var_node.u.op.var;
 +              }
  
 -      lcname = zend_str_tolower_dup(Z_STRVAL(class_name->u.constant), Z_STRLEN(class_name->u.constant));
 +              if (op_array->fn_flags & ZEND_ACC_VARIADIC) {
 +                      zend_error_noreturn(E_COMPILE_ERROR, "Only the last parameter can be variadic");
 +              }
  
 -      if (!(strcmp(lcname, "self") && strcmp(lcname, "parent"))) {
 -              efree(lcname);
 -              zend_error_noreturn(E_COMPILE_ERROR, "Cannot use '%s' as class name as it is reserved", Z_STRVAL(class_name->u.constant));
 -      }
 +              if (is_variadic) {
 +                      opcode = ZEND_RECV_VARIADIC;
 +                      default_node.op_type = IS_UNUSED;
 +                      op_array->fn_flags |= ZEND_ACC_VARIADIC;
  
 -      /* Class name must not conflict with import names */
 -      if (CG(current_import) &&
 -          zend_hash_find(CG(current_import), lcname, Z_STRLEN(class_name->u.constant)+1, (void**)&ns_name) == SUCCESS) {
 -              error = 1;
 -      }
 +                      if (default_ast) {
 +                              zend_error_noreturn(E_COMPILE_ERROR,
 +                                      "Variadic parameter cannot have a default value");
 +                      }
 +              } else if (default_ast) {
 +                      opcode = ZEND_RECV_INIT;
 +                      default_node.op_type = IS_CONST;
 +                      zend_const_expr_to_zval(&default_node.u.constant, default_ast TSRMLS_CC);
 +              } else {
 +                      opcode = ZEND_RECV;
 +                      default_node.op_type = IS_UNUSED;
 +                      op_array->required_num_args = i + 1;
 +              }
 +
 +              opline = zend_emit_op(NULL, opcode, NULL, &default_node TSRMLS_CC);
 +              SET_NODE(opline->result, &var_node);
 +              opline->op1.num = i + 1;
 +
 +              arg_info = &arg_infos[i];
 +              arg_info->name = estrndup(name->val, name->len);
 +              arg_info->name_len = (uint32_t)name->len;
 +              arg_info->pass_by_reference = is_ref;
 +              arg_info->is_variadic = is_variadic;
 +              arg_info->type_hint = 0;
 +              arg_info->allow_null = 1;
 +              arg_info->class_name = NULL;
 +              arg_info->class_name_len = 0;
 +
 +              if (type_ast) {
 +                      zend_bool has_null_default = default_ast
 +                              && (Z_TYPE(default_node.u.constant) == IS_NULL
 +                                      || (Z_TYPE(default_node.u.constant) == IS_CONSTANT
-                                               && strcasecmp(Z_STRVAL(default_node.u.constant), "NULL") == 0)
-                                       || Z_TYPE(default_node.u.constant) == IS_CONSTANT_AST); // ???
++                                              && strcasecmp(Z_STRVAL(default_node.u.constant), "NULL") == 0));
 +
 +                      op_array->fn_flags |= ZEND_ACC_HAS_TYPE_HINTS;
 +                      arg_info->allow_null = has_null_default;
 +
 +                      if (type_ast->kind == ZEND_AST_TYPE) {
 +                              arg_info->type_hint = type_ast->attr;
 +                              if (arg_info->type_hint == IS_ARRAY) {
 +                                      if (default_ast && !has_null_default
 +                                              && Z_TYPE(default_node.u.constant) != IS_ARRAY
++                                              && !Z_CONSTANT(default_node.u.constant)
 +                                      ) {
 +                                              zend_error_noreturn(E_COMPILE_ERROR, "Default value for parameters "
 +                                                      "with array type hint can only be an array or NULL");
 +                                      }
 +                              } else if (arg_info->type_hint == IS_CALLABLE && default_ast) {
-                                       if (!has_null_default) {
++                                      if (!has_null_default && !Z_CONSTANT(default_node.u.constant)) {
 +                                              zend_error_noreturn(E_COMPILE_ERROR, "Default value for parameters "
 +                                                      "with callable type hint can only be NULL");
 +                                      }
 +                              }
 +                      } else {
 +                              zend_string *class_name = zend_ast_get_str(type_ast);
  
 -      if (CG(current_namespace)) {
 -              /* Prefix class name with name of current namespace */
 -              znode tmp;
 +                              if (zend_is_const_default_class_ref(type_ast)) {
 +                                      class_name = zend_resolve_class_name_ast(type_ast TSRMLS_CC);
 +                              } else {
 +                                      zend_string_addref(class_name);
 +                              }
  
 -              tmp.op_type = IS_CONST;
 -              tmp.u.constant = *CG(current_namespace);
 -              zval_copy_ctor(&tmp.u.constant);
 -              zend_do_build_namespace_name(&tmp, &tmp, class_name TSRMLS_CC);
 -              *class_name = tmp;
 -              efree(lcname);
 -              lcname = zend_str_tolower_dup(Z_STRVAL(class_name->u.constant), Z_STRLEN(class_name->u.constant));
 -      }
 +                              arg_info->type_hint = IS_OBJECT;
 +                              arg_info->class_name = estrndup(class_name->val, class_name->len);
 +                              arg_info->class_name_len = (uint32_t)class_name->len;
  
 -      if (error) {
 -              char *tmp = zend_str_tolower_dup(Z_STRVAL_PP(ns_name), Z_STRLEN_PP(ns_name));
 +                              zend_string_release(class_name);
  
-                               if (default_ast && !has_null_default) {
 -              if (Z_STRLEN_PP(ns_name) != Z_STRLEN(class_name->u.constant) ||
 -                      memcmp(tmp, lcname, Z_STRLEN(class_name->u.constant))) {
 -                      zend_error_noreturn(E_COMPILE_ERROR, "Cannot declare class %s because the name is already in use", Z_STRVAL(class_name->u.constant));
++                              if (default_ast && !has_null_default && !Z_CONSTANT(default_node.u.constant)) {
 +                                              zend_error_noreturn(E_COMPILE_ERROR, "Default value for parameters "
 +                                                      "with a class type hint can only be NULL");
 +                              }
 +                      }
                }
 -              efree(tmp);
        }
  
 -      new_class_entry = emalloc(sizeof(zend_class_entry));
 -      new_class_entry->type = ZEND_USER_CLASS;
 -      new_class_entry->name = zend_new_interned_string(Z_STRVAL(class_name->u.constant), Z_STRLEN(class_name->u.constant) + 1, 1 TSRMLS_CC);
 -      new_class_entry->name_length = Z_STRLEN(class_name->u.constant);
 -
 -      zend_initialize_class_data(new_class_entry, 1 TSRMLS_CC);
 -      new_class_entry->info.user.filename = zend_get_compiled_filename(TSRMLS_C);
 -      new_class_entry->info.user.line_start = class_token->u.op.opline_num;
 -      new_class_entry->ce_flags |= class_token->EA;
 -
 -      if (parent_class_name && parent_class_name->op_type != IS_UNUSED) {
 -              switch (parent_class_name->EA) {
 -                      case ZEND_FETCH_CLASS_SELF:
 -                              zend_error_noreturn(E_COMPILE_ERROR, "Cannot use 'self' as class name as it is reserved");
 -                              break;
 -                      case ZEND_FETCH_CLASS_PARENT:
 -                              zend_error_noreturn(E_COMPILE_ERROR, "Cannot use 'parent' as class name as it is reserved");
 -                              break;
 -                      case ZEND_FETCH_CLASS_STATIC:
 -                              zend_error_noreturn(E_COMPILE_ERROR, "Cannot use 'static' as class name as it is reserved");
 -                              break;
 -                      default:
 -                              break;
 -              }
 -              doing_inheritance = 1;
 -      }
 +      /* These are assigned at the end to avoid unitialized memory in case of an error */
 +      op_array->num_args = list->children;
 +      op_array->arg_info = arg_infos;
 +}
 +/* }}} */
  
 -      opline = get_next_op(CG(active_op_array) TSRMLS_CC);
 -      opline->op1_type = IS_CONST;
 -      build_runtime_defined_function_key(&key, lcname, new_class_entry->name_length TSRMLS_CC);
 -      opline->op1.constant = zend_add_literal(CG(active_op_array), &key TSRMLS_CC);
 -      Z_HASH_P(&CONSTANT(opline->op1.constant)) = zend_hash_func(Z_STRVAL(CONSTANT(opline->op1.constant)), Z_STRLEN(CONSTANT(opline->op1.constant)));
 +void zend_compile_closure_uses(zend_ast *ast TSRMLS_DC) /* {{{ */
 +{
 +      zend_ast_list *list = zend_ast_get_list(ast);
 +      uint32_t i;
  
 -      opline->op2_type = IS_CONST;
 +      for (i = 0; i < list->children; ++i) {
 +              zend_ast *var_ast = list->child[i];
 +              zend_string *name = zend_ast_get_str(var_ast);
 +              zend_bool by_ref = var_ast->attr;
 +              zval zv;
  
 -      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_noreturn(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);
 +              if (zend_string_equals_literal(name, "this")) {
 +                      zend_error_noreturn(E_COMPILE_ERROR, "Cannot use $this as lexical variable");
                }
  
 -              opline->extended_value = parent_class_name->u.op.var;
 -              opline->opcode = ZEND_DECLARE_INHERITED_CLASS;
 -      } else {
 -              opline->opcode = ZEND_DECLARE_CLASS;
 -      }
 -
 -      LITERAL_STRINGL(opline->op2, lcname, new_class_entry->name_length, 0);
 -      CALCULATE_LITERAL_HASH(opline->op2.constant);
 -
 -      zend_hash_quick_update(CG(class_table), Z_STRVAL(key), Z_STRLEN(key), Z_HASH_P(&CONSTANT(opline->op1.constant)), &new_class_entry, sizeof(zend_class_entry *), NULL);
 -      CG(active_class_entry) = new_class_entry;
 -
 -      opline->result.var = get_temporary_variable(CG(active_op_array));
 -      opline->result_type = IS_VAR;
 -      GET_NODE(&CG(implementing_class), opline->result);
 +              ZVAL_NULL(&zv);
 +              Z_CONST_FLAGS(zv) = by_ref ? IS_LEXICAL_REF : IS_LEXICAL_VAR;
  
 -      if (CG(doc_comment)) {
 -              CG(active_class_entry)->info.user.doc_comment = CG(doc_comment);
 -              CG(active_class_entry)->info.user.doc_comment_len = CG(doc_comment_len);
 -              CG(doc_comment) = NULL;
 -              CG(doc_comment_len) = 0;
 +              zend_compile_static_var_common(var_ast, &zv, by_ref TSRMLS_CC);
        }
  }
  /* }}} */
index d6f551bcdf1f8c23b5e32704574f37a7eb31115f,7ef6d1c3e6d63d41568bf9ec14ea606fe081d86e..9ac6c50410eaa2e2172bb2451590867cf956d82f
@@@ -568,13 -605,25 +568,28 @@@ ZEND_API void zend_verify_arg_error(in
        } else {
                zend_error(error_type, "Argument %d passed to %s%s%s() must %s%s, %s%s given", arg_num, fclass, fsep, fname, need_msg, need_kind, given_msg, given_kind);
        }
 -      return 0;
 +
 +      if (arg && zf->common.type == ZEND_USER_FUNCTION) {
 +              ZVAL_COPY_VALUE(arg, &old_arg);
 +      }
  }
  
- static void zend_verify_arg_type(zend_function *zf, uint32_t arg_num, zval *arg TSRMLS_DC)
+ static int is_null_constant(zval *default_value)
+ {
 -      if (IS_CONSTANT_TYPE(Z_TYPE_P(default_value))) {
 -              zval constant = *default_value;
 -              zval *constant_ptr = &constant;
++      if (Z_CONSTANT_P(default_value)) {
++              zval constant;
 -              zval_update_constant(&constant_ptr, 0 TSRMLS_CC);
++              ZVAL_COPY_VALUE(&constant, default_value);
++              zval_update_constant(&constant, 0 TSRMLS_CC);
+               if (Z_TYPE(constant) == IS_NULL) {
+                       return 1;
+               }
+               zval_dtor(&constant);
+       }
+       return 0;
+ }
 -static inline int zend_verify_arg_type(zend_function *zf, zend_uint arg_num, zval *arg, ulong fetch_type, zval *default_value TSRMLS_DC)
++static void zend_verify_arg_type(zend_function *zf, uint32_t arg_num, zval *arg, zval *default_value TSRMLS_DC)
  {
        zend_arg_info *cur_arg_info;
        char *need_msg;
        }
  
        if (cur_arg_info->class_name) {
 -              const char *class_name;
 +              char *class_name;
  
 -              if (!arg) {
 -                      need_msg = zend_verify_arg_class_kind(cur_arg_info, fetch_type, &class_name, &ce TSRMLS_CC);
 -                      return zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, need_msg, class_name, "none", "" TSRMLS_CC);
 -              }
 +              ZVAL_DEREF(arg);
                if (Z_TYPE_P(arg) == IS_OBJECT) {
 -                      need_msg = zend_verify_arg_class_kind(cur_arg_info, fetch_type, &class_name, &ce TSRMLS_CC);
 +                      need_msg = zend_verify_arg_class_kind(cur_arg_info, &class_name, &ce TSRMLS_CC);
                        if (!ce || !instanceof_function(Z_OBJCE_P(arg), ce TSRMLS_CC)) {
 -                              return zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, need_msg, class_name, "instance of ", Z_OBJCE_P(arg)->name TSRMLS_CC);
 +                              zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, need_msg, class_name, "instance of ", Z_OBJCE_P(arg)->name->val, arg TSRMLS_CC);
                        }
-               } else if (Z_TYPE_P(arg) != IS_NULL || !cur_arg_info->allow_null) {
+               } else if (Z_TYPE_P(arg) != IS_NULL || !(cur_arg_info->allow_null || (default_value && is_null_constant(default_value)))) {
 -                      need_msg = zend_verify_arg_class_kind(cur_arg_info, fetch_type, &class_name, &ce TSRMLS_CC);
 -                      return zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, need_msg, class_name, zend_zval_type_name(arg), "" TSRMLS_CC);
 +                      need_msg = zend_verify_arg_class_kind(cur_arg_info, &class_name, &ce TSRMLS_CC);
 +                      zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, need_msg, class_name, zend_zval_type_name(arg), "", arg TSRMLS_CC);
                }
        } else if (cur_arg_info->type_hint) {
 -              switch(cur_arg_info->type_hint) {
 -                      case IS_ARRAY:
 -                              if (!arg) {
 -                                      return zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be of the type array", "", "none", "" TSRMLS_CC);
 -                              }
 +              if (cur_arg_info->type_hint == IS_ARRAY) {
 +                      ZVAL_DEREF(arg);
-                       if (Z_TYPE_P(arg) != IS_ARRAY && (Z_TYPE_P(arg) != IS_NULL || !cur_arg_info->allow_null)) {
++                      if (Z_TYPE_P(arg) != IS_ARRAY && (Z_TYPE_P(arg) != IS_NULL || !(cur_arg_info->allow_null || (default_value && is_null_constant(default_value))))) {
 +                              zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be of the type array", "", zend_zval_type_name(arg), "", arg TSRMLS_CC);
 +                      }
 +              } else if (cur_arg_info->type_hint == IS_CALLABLE) {
-                       if (!zend_is_callable(arg, IS_CALLABLE_CHECK_SILENT, NULL TSRMLS_CC) && (Z_TYPE_P(arg) != IS_NULL || !cur_arg_info->allow_null)) {
++                      if (!zend_is_callable(arg, IS_CALLABLE_CHECK_SILENT, NULL TSRMLS_CC) && (Z_TYPE_P(arg) != IS_NULL || !(cur_arg_info->allow_null || (default_value && is_null_constant(default_value))))) {
 +                              zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be callable", "", zend_zval_type_name(arg), "", arg TSRMLS_CC);
 +                      }
 +#if ZEND_DEBUG
 +              } else {
 +                      zend_error(E_ERROR, "Unknown typehint");
 +#endif
 +              }
 +      }
 +}
  
 -                              if (Z_TYPE_P(arg) != IS_ARRAY && (Z_TYPE_P(arg) != IS_NULL || !(cur_arg_info->allow_null || (default_value && is_null_constant(default_value))))) {
 -                                      return zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be of the type array", "", zend_zval_type_name(arg), "" TSRMLS_CC);
 -                              }
 -                              break;
 +static inline int zend_verify_missing_arg_type(zend_function *zf, uint32_t arg_num TSRMLS_DC)
 +{
 +      zend_arg_info *cur_arg_info;
 +      char *need_msg;
 +      zend_class_entry *ce;
  
 -                      case IS_CALLABLE:
 -                              if (!arg) {
 -                                      return zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be callable", "", "none", "" TSRMLS_CC);
 -                              }
 -                              if (!zend_is_callable(arg, IS_CALLABLE_CHECK_SILENT, NULL TSRMLS_CC) && (Z_TYPE_P(arg) != IS_NULL || !(cur_arg_info->allow_null || (default_value && is_null_constant(default_value))))) {
 -                                      return zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be callable", "", zend_zval_type_name(arg), "" TSRMLS_CC);
 -                              }
 -                              break;
 +      if (UNEXPECTED(!zf->common.arg_info)) {
 +              return 1;
 +      }
  
 -                      default:
 -                              zend_error(E_ERROR, "Unknown typehint");
 +      if (EXPECTED(arg_num <= zf->common.num_args)) {
 +              cur_arg_info = &zf->common.arg_info[arg_num-1];
 +      } else if (zf->common.fn_flags & ZEND_ACC_VARIADIC) {
 +              cur_arg_info = &zf->common.arg_info[zf->common.num_args-1];
 +      } else {
 +              return 1;
 +      }
 +
 +      if (cur_arg_info->class_name) {
 +              char *class_name;
 +
 +              need_msg = zend_verify_arg_class_kind(cur_arg_info, &class_name, &ce TSRMLS_CC);
 +              zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, need_msg, class_name, "none", "", NULL TSRMLS_CC);
 +              return 0;
 +      } else if (cur_arg_info->type_hint) {
 +              if (cur_arg_info->type_hint == IS_ARRAY) {
 +                      zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be of the type array", "", "none", "", NULL TSRMLS_CC);
 +              } else if (cur_arg_info->type_hint == IS_CALLABLE) {
 +                      zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be callable", "", "none", "", NULL TSRMLS_CC);
 +#if ZEND_DEBUG
 +              } else {
 +                      zend_error(E_ERROR, "Unknown typehint");
 +#endif
                }
 +              return 0;
        }
        return 1;
  }
index ec9841c0f2ab0d126afd041556cc0161d537dd0c,03fa7cf09b756ef213f1c5a23e486e40bc123d0e..223f43dda784ee8d49a6a1fc099caa666370555b
@@@ -2461,351 -2721,122 +2461,351 @@@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_
                                        CHECK_EXCEPTION();
                                        ZEND_VM_NEXT_OPCODE();
                                }
 -                              call->called_scope = ce;
 -                              call->object = NULL;
  
 -                              if (ce->get_static_method) {
 -                                      call->fbc = ce->get_static_method(ce, Z_STRVAL_PP(method), Z_STRLEN_PP(method) TSRMLS_CC);
 +                              if (called_scope->get_static_method) {
 +                                      fbc = called_scope->get_static_method(called_scope, Z_STR_P(method) TSRMLS_CC);
 +                              } else {
 +                                      fbc = zend_std_get_static_method(called_scope, Z_STR_P(method), NULL TSRMLS_CC);
 +                              }
 +                              if (UNEXPECTED(fbc == NULL)) {
 +                                      zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", called_scope->name->val, Z_STRVAL_P(method));
 +                              }
 +                              if (!(fbc->common.fn_flags & ZEND_ACC_STATIC)) {
 +                                      if (fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) {
 +                                              zend_error(E_STRICT,
 +                                              "Non-static method %s::%s() should not be called statically",
 +                                              fbc->common.scope->name->val, fbc->common.function_name->val);
 +                                      } else {
 +                                              zend_error_noreturn(
 +                                                      E_ERROR,
 +                                                      "Non-static method %s::%s() cannot be called statically",
 +                                                      fbc->common.scope->name->val, fbc->common.function_name->val);
 +                                      }
 +                              }
 +                      } else {
 +                              called_scope = Z_OBJCE_P(obj);
 +                              object = Z_OBJ_P(obj);
 +
 +                              fbc = Z_OBJ_HT_P(obj)->get_method(&object, Z_STR_P(method), NULL TSRMLS_CC);
 +                              if (UNEXPECTED(fbc == NULL)) {
 +                                      zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", object->ce->name->val, Z_STRVAL_P(method));
 +                              }
 +
 +                              if ((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) {
 +                                      object = NULL;
 +                              } else {
 +                                      GC_REFCOUNT(object)++; /* For $this pointer */
 +                              }
 +                      }
 +                      FREE_OP2();
 +              } else {
 +                      if (UNEXPECTED(EG(exception) != NULL)) {
 +                              HANDLE_EXCEPTION();
 +                      }
 +                      zend_error_noreturn(E_ERROR, "Function name must be a string");
 +                      ZEND_VM_CONTINUE(); /* Never reached */
 +              }
 +              EX(call) = zend_vm_stack_push_call_frame(VM_FRAME_NESTED_FUNCTION,
 +                      fbc, opline->extended_value, called_scope, object, EX(call) TSRMLS_CC);
 +
 +              CHECK_EXCEPTION();
 +              ZEND_VM_NEXT_OPCODE();
 +      }
 +}
 +
 +ZEND_VM_HANDLER(118, ZEND_INIT_USER_CALL, CONST, CONST|TMP|VAR|CV)
 +{
 +      USE_OPLINE
 +      zend_free_op free_op2;
 +      zval *function_name = GET_OP2_ZVAL_PTR_DEREF(BP_VAR_R);
 +      zend_fcall_info_cache fcc;
 +      char *error = NULL;
 +      zend_function *func;
 +      zend_class_entry *called_scope;
 +      zend_object *object;
 +
 +      if (zend_is_callable_ex(function_name, NULL, 0, NULL, &fcc, &error TSRMLS_CC)) {
 +              if (error) {
 +                      efree(error);
 +              }
 +              func = fcc.function_handler;
 +              if (func->common.fn_flags & ZEND_ACC_CLOSURE) {
 +                      /* Delay closure destruction until its invocation */
 +                      func->common.prototype = (zend_function*)Z_OBJ_P(function_name);
 +                      Z_ADDREF_P(function_name);
 +              }
 +              called_scope = fcc.called_scope;
 +              object = fcc.object;
 +              if (object) {
 +                      GC_REFCOUNT(object)++; /* For $this pointer */
 +              } else if (func->common.scope &&
 +                         !(func->common.fn_flags & ZEND_ACC_STATIC)) {
 +                      if (func->common.fn_flags & ZEND_ACC_ALLOW_STATIC) {
 +                              zend_error(E_STRICT,
 +                              "Non-static method %s::%s() should not be called statically",
 +                              func->common.scope->name->val, func->common.function_name->val);
 +                      } else {
 +                              zend_error_noreturn(
 +                                      E_ERROR,
 +                                      "Non-static method %s::%s() cannot be called statically",
 +                                      func->common.scope->name->val, func->common.function_name->val);
 +                      }
 +              }
 +      } else {
 +              zend_error(E_WARNING, "%s() expects parameter 1 to be a valid callback, %s", Z_STRVAL_P(opline->op1.zv), error);
 +              efree(error);
 +              func = (zend_function*)&zend_pass_function;
 +              called_scope = NULL;
 +              object = NULL;
 +      }
 +
 +      EX(call) = zend_vm_stack_push_call_frame(VM_FRAME_NESTED_FUNCTION,
 +              func, opline->extended_value, called_scope, object, EX(call) TSRMLS_CC);
 +
 +      FREE_OP2();
 +      CHECK_EXCEPTION();
 +      ZEND_VM_NEXT_OPCODE();
 +}
 +
 +ZEND_VM_HANDLER(69, ZEND_INIT_NS_FCALL_BY_NAME, ANY, CONST)
 +{
 +      USE_OPLINE
 +      zval *func_name;
 +      zval *func;
 +      zend_function *fbc;
 +
 +      func_name = opline->op2.zv + 1;
 +      if (CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv))) {
 +              fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv));
 +      } else if ((func = zend_hash_find(EG(function_table), Z_STR_P(func_name))) == NULL) {
 +              func_name++;
 +              if (UNEXPECTED((func = zend_hash_find(EG(function_table), Z_STR_P(func_name))) == NULL)) {
 +                      SAVE_OPLINE();
 +                      zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv));
 +              } else {
 +                      fbc = Z_FUNC_P(func);
 +                      CACHE_PTR(Z_CACHE_SLOT_P(opline->op2.zv), fbc);
 +              }
 +      } else {
 +              fbc = Z_FUNC_P(func);
 +              CACHE_PTR(Z_CACHE_SLOT_P(opline->op2.zv), fbc);
 +      }
 +
 +      EX(call) = zend_vm_stack_push_call_frame(VM_FRAME_NESTED_FUNCTION,
 +              fbc, opline->extended_value, NULL, NULL, EX(call) TSRMLS_CC);
 +
 +      ZEND_VM_NEXT_OPCODE();
 +}
 +
 +ZEND_VM_HANDLER(61, ZEND_INIT_FCALL, ANY, CONST)
 +{
 +      USE_OPLINE
 +      zend_free_op free_op2;
 +      zval *fname = GET_OP2_ZVAL_PTR(BP_VAR_R);
 +      zval *func;
 +      zend_function *fbc;
 +
 +      if (CACHED_PTR(Z_CACHE_SLOT_P(fname))) {
 +              fbc = CACHED_PTR(Z_CACHE_SLOT_P(fname));
 +      } else if (UNEXPECTED((func = zend_hash_find(EG(function_table), Z_STR_P(fname))) == NULL)) {
 +          SAVE_OPLINE();
 +              zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(fname));
 +      } else {
 +              fbc = Z_FUNC_P(func);
 +              CACHE_PTR(Z_CACHE_SLOT_P(fname), fbc);
 +      }
 +
 +      EX(call) = zend_vm_stack_push_call_frame(VM_FRAME_NESTED_FUNCTION,
 +              fbc, opline->extended_value, NULL, NULL, EX(call) TSRMLS_CC);
 +
 +      FREE_OP2();
 +
 +      ZEND_VM_NEXT_OPCODE();
 +}
 +
 +ZEND_VM_HANDLER(60, ZEND_DO_FCALL, ANY, ANY)
 +{
 +      USE_OPLINE
 +      zend_execute_data *call = EX(call);
 +      zend_function *fbc = call->func;
 +      zend_object *object = Z_OBJ(call->This);
 +
 +      SAVE_OPLINE();
 +      EX(call) = call->prev_execute_data;
 +      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->val, fbc->common.function_name->val);
 +              }
 +              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->val : "",
 +                              fbc->common.scope ? "::" : "",
 +                              fbc->common.function_name->val);
 +                      if (UNEXPECTED(EG(exception) != NULL)) {
 +                              HANDLE_EXCEPTION();
 +                      }
 +              }
 +      }
 +
 +      LOAD_OPLINE();
 +
 +      if (UNEXPECTED(fbc->type == ZEND_INTERNAL_FUNCTION)) {
 +              int should_change_scope = 0;
 +              zval *ret;
 +
 +              if (fbc->common.scope) {
 +                      should_change_scope = 1;
 +                      /* TODO: we don't set scope if we call an object method ??? */
 +                      /* See: ext/pdo_sqlite/tests/pdo_fetch_func_001.phpt */
 +#if 1
 +                      EG(scope) = object ? NULL : fbc->common.scope;
 +#else 
 +                      EG(scope) = fbc->common.scope;
 +#endif
 +              } else {                        
 +                      call->called_scope = EX(called_scope);
 +                      Z_OBJ(call->This) = Z_OBJ(EX(This));
 +              }
 +
 +              call->prev_execute_data = execute_data;
 +              EG(current_execute_data) = call;
 +
 +              if (fbc->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) {
 +                      uint32_t i;
 +                      zval *p = ZEND_CALL_ARG(call, 1);
 +
 +                      for (i = 0; i < call->num_args; ++i) {
-                               zend_verify_arg_type(fbc, i + 1, p TSRMLS_CC);
++                              zend_verify_arg_type(fbc, i + 1, p, NULL TSRMLS_CC);
 +                              p++;
 +                      }
 +                      if (UNEXPECTED(EG(exception) != NULL)) {
 +                              EG(current_execute_data) = call->prev_execute_data;             
 +                              zend_vm_stack_free_args(call TSRMLS_CC);
 +                              zend_vm_stack_free_call_frame(call TSRMLS_CC);
 +                              if (RETURN_VALUE_USED(opline)) {
 +                                      ZVAL_UNDEF(EX_VAR(opline->result.var));
 +                              }
 +                              if (UNEXPECTED(should_change_scope)) {
 +                                      ZEND_VM_C_GOTO(fcall_end_change_scope);
                                } else {
 -                                      call->fbc = zend_std_get_static_method(ce, Z_STRVAL_PP(method), Z_STRLEN_PP(method), NULL TSRMLS_CC);
 +                                      ZEND_VM_C_GOTO(fcall_end);
                                }
 -                      } else {
 -                              call->object = *obj;
 -                              ce = call->called_scope = Z_OBJCE_PP(obj);
 +                      }
 +              }
  
 -                              call->fbc = Z_OBJ_HT_P(call->object)->get_method(&call->object, Z_STRVAL_PP(method), Z_STRLEN_PP(method), NULL TSRMLS_CC);
 -                              if (UNEXPECTED(call->fbc == NULL)) {
 -                                      zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), Z_STRVAL_PP(method));
 -                              }
 +              ret = EX_VAR(opline->result.var);
 +              ZVAL_NULL(ret);
 +              Z_VAR_FLAGS_P(ret) = (fbc->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0 ? IS_VAR_RET_REF : 0;
  
 -                              if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) {
 -                                      call->object = NULL;
 -                              } else {
 -                                      if (!PZVAL_IS_REF(call->object)) {
 -                                              Z_ADDREF_P(call->object); /* For $this pointer */
 -                                      } else {
 -                                              zval *this_ptr;
 -                                              ALLOC_ZVAL(this_ptr);
 -                                              INIT_PZVAL_COPY(this_ptr, call->object);
 -                                              zval_copy_ctor(this_ptr);
 -                                              call->object = this_ptr;
 -                                      }
 -                              }
 +              if (!zend_execute_internal) {
 +                      /* saves one function call if zend_execute_internal is not used */
 +                      fbc->internal_function.handler(call, ret TSRMLS_CC);
 +              } else {
 +                      zend_execute_internal(call, ret TSRMLS_CC);
 +              }
 +              EG(current_execute_data) = call->prev_execute_data;             
 +              zend_vm_stack_free_args(call TSRMLS_CC);
 +              zend_vm_stack_free_call_frame(call TSRMLS_CC);
 +
 +              if (!RETURN_VALUE_USED(opline)) {
 +                      zval_ptr_dtor(ret);
 +              }
 +
 +              if (UNEXPECTED(should_change_scope)) {
 +                      ZEND_VM_C_GOTO(fcall_end_change_scope);
 +              } else {
 +                      ZEND_VM_C_GOTO(fcall_end);
 +              }
 +      } else if (EXPECTED(fbc->type == ZEND_USER_FUNCTION)) {
 +              call->scope = EG(scope) = fbc->common.scope;
 +              if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_GENERATOR) != 0)) {
 +                      if (RETURN_VALUE_USED(opline)) {
 +                              zend_generator_create_zval(call, &fbc->op_array, EX_VAR(opline->result.var) TSRMLS_CC);
 +                      } else {
 +                              zend_vm_stack_free_args(call TSRMLS_CC);
                        }
 +      
 +                      zend_vm_stack_free_call_frame(call TSRMLS_CC);
 +              } else {
 +                      zval *return_value = NULL;
 +
 +                      call->symbol_table = NULL;
 +                      if (RETURN_VALUE_USED(opline)) {
 +                              return_value = EX_VAR(opline->result.var);
  
 -                      if (UNEXPECTED(call->fbc == NULL)) {
 -                              zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name, Z_STRVAL_PP(method));
 +                              ZVAL_NULL(return_value);
 +                              Z_VAR_FLAGS_P(return_value) = 0;
                        }
  
 -                      call->num_additional_args = 0;
 -                      call->is_ctor_call = 0;
 -                      EX(call) = call;
 +                      call->prev_execute_data = execute_data;
 +                      i_init_func_execute_data(call, &fbc->op_array, return_value TSRMLS_CC);
  
 -                      FREE_OP2();
 -                      CHECK_EXCEPTION();
 -                      ZEND_VM_NEXT_OPCODE();
 -              } else {
 -                      if (UNEXPECTED(EG(exception) != NULL)) {
 -                              HANDLE_EXCEPTION();
 +                      if (EXPECTED(zend_execute_ex == execute_ex)) {
 +                              ZEND_VM_ENTER();
 +                      } else {
 +                              call->frame_info = VM_FRAME_INFO(
 +                                      VM_FRAME_TOP_FUNCTION,
 +                                      VM_FRAME_FLAGS(call->frame_info));
 +                              zend_execute_ex(call TSRMLS_CC);
                        }
 -                      zend_error_noreturn(E_ERROR, "Function name must be a string");
 -                      ZEND_VM_NEXT_OPCODE(); /* Never reached */
                }
 -      }
 -}
 -
 +      } else { /* ZEND_OVERLOADED_FUNCTION */
 +              EG(scope) = fbc->common.scope;
  
 -ZEND_VM_HANDLER(69, ZEND_INIT_NS_FCALL_BY_NAME, ANY, CONST)
 -{
 -      USE_OPLINE
 -      zend_literal *func_name;
 -      call_slot *call = EX(call_slots) + opline->result.num;
 +              ZVAL_NULL(EX_VAR(opline->result.var));
  
 -      func_name = opline->op2.literal + 1;
 -      if (CACHED_PTR(opline->op2.literal->cache_slot)) {
 -              call->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 **) &call->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 **) &call->fbc)==FAILURE)) {
 -                      SAVE_OPLINE();
 -                      zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv));
 +              /* Not sure what should be done here if it's a static method */
 +              if (EXPECTED(object != NULL)) {
 +                      call->prev_execute_data = execute_data;
 +                      EG(current_execute_data) = call;
 +                      object->handlers->call_method(fbc->common.function_name, object, call, EX_VAR(opline->result.var) TSRMLS_CC);
 +                      EG(current_execute_data) = call->prev_execute_data;
                } else {
 -                      CACHE_PTR(opline->op2.literal->cache_slot, call->fbc);
 +                      zend_error_noreturn(E_ERROR, "Cannot call overloaded function for non-object");
                }
 -      } else {
 -              CACHE_PTR(opline->op2.literal->cache_slot, call->fbc);
 -      }
  
 -      call->object = NULL;
 -      call->called_scope = NULL;
 -      call->num_additional_args = 0;
 -      call->is_ctor_call = 0;
 +              zend_vm_stack_free_args(call TSRMLS_CC);
  
 -      EX(call) = call;
 -      ZEND_VM_NEXT_OPCODE();
 -}
 -
 -ZEND_VM_HANDLER(61, ZEND_DO_FCALL_BY_NAME, ANY, ANY)
 -{
 -      EX(function_state).function = EX(call)->fbc;
 -      ZEND_VM_DISPATCH_TO_HELPER(zend_do_fcall_common_helper);
 -}
 +              zend_vm_stack_free_call_frame(call TSRMLS_CC);
  
 -ZEND_VM_HANDLER(60, ZEND_DO_FCALL, CONST, ANY)
 -{
 -      USE_OPLINE
 -      zend_free_op free_op1;
 -      zval *fname = GET_OP1_ZVAL_PTR(BP_VAR_R);
 -      call_slot *call = EX(call_slots) + opline->op2.num;
 +              if (fbc->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) {
 +                      zend_string_release(fbc->common.function_name);
 +              }
 +              efree(fbc);
  
 -      if (CACHED_PTR(opline->op1.literal->cache_slot)) {
 -              EX(function_state).function = CACHED_PTR(opline->op1.literal->cache_slot);
 -      } else if (UNEXPECTED(zend_hash_quick_find(EG(function_table), Z_STRVAL_P(fname), Z_STRLEN_P(fname)+1, Z_HASH_P(fname), (void **) &EX(function_state).function)==FAILURE)) {
 -          SAVE_OPLINE();
 -              zend_error_noreturn(E_ERROR, "Call to undefined function %s()", fname->value.str.val);
 -      } else {
 -              CACHE_PTR(opline->op1.literal->cache_slot, EX(function_state).function);
 +              if (!RETURN_VALUE_USED(opline)) {
 +                      zval_ptr_dtor(EX_VAR(opline->result.var));
 +              } else {
 +//???                 Z_UNSET_ISREF_P(EX_T(opline->result.var).var.ptr);
 +//???                 Z_SET_REFCOUNT_P(EX_T(opline->result.var).var.ptr, 1);
 +                      Z_VAR_FLAGS_P(EX_VAR(opline->result.var)) = 0;
 +              }
        }
  
 -      call->fbc = EX(function_state).function;
 -      call->object = NULL;
 -      call->called_scope = NULL;
 -      call->num_additional_args = 0;
 -      call->is_ctor_call = 0;
 -      EX(call) = call;
 +ZEND_VM_C_LABEL(fcall_end_change_scope):
 +      if (object) {
 +              if (UNEXPECTED(EG(exception) != NULL) && (opline->op1.num & ZEND_CALL_CTOR)) {
 +                      if (!(opline->op1.num & ZEND_CALL_CTOR_RESULT_UNUSED)) {
 +                              GC_REFCOUNT(object)--;
 +                      }
 +                      if (GC_REFCOUNT(object) == 1) {
 +                              zend_object_store_ctor_failed(object TSRMLS_CC);
 +                      }
 +              }
 +              OBJ_RELEASE(object);
 +      }
 +      EG(scope) = EX(scope);
  
 -      FREE_OP1();
 +ZEND_VM_C_LABEL(fcall_end):
 +      if (UNEXPECTED(EG(exception) != NULL)) {
 +              zend_throw_exception_internal(NULL TSRMLS_CC);
 +              if (RETURN_VALUE_USED(opline)) {
 +                      zval_ptr_dtor(EX_VAR(opline->result.var));
 +              }
 +              HANDLE_EXCEPTION();
 +      }
  
 -      ZEND_VM_DISPATCH_TO_HELPER(zend_do_fcall_common_helper);
 +      ZEND_VM_NEXT_OPCODE();
  }
  
  ZEND_VM_HANDLER(62, ZEND_RETURN, CONST|TMP|VAR|CV, ANY)
@@@ -3514,48 -3407,41 +3514,48 @@@ ZEND_VM_HANDLER(120, ZEND_SEND_USER, VA
        ZEND_VM_NEXT_OPCODE();
  }
  
-               zend_verify_arg_type(EX(func), arg_num, param TSRMLS_CC);
 +ZEND_VM_HANDLER(63, ZEND_RECV, ANY, ANY)
 +{
 +      USE_OPLINE
 +      uint32_t arg_num = opline->op1.num;
 +
 +      SAVE_OPLINE();
 +      if (UNEXPECTED(arg_num > EX(num_args))) {
 +              zend_verify_missing_arg(execute_data, arg_num TSRMLS_CC);
 +              CHECK_EXCEPTION();
 +      } else if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) {
 +              zval *param = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->result.var TSRMLS_CC);
 +
++              zend_verify_arg_type(EX(func), arg_num, param, NULL TSRMLS_CC);
 +              CHECK_EXCEPTION();
 +      }
 +
 +      ZEND_VM_NEXT_OPCODE();
 +}
 +
  ZEND_VM_HANDLER(64, ZEND_RECV_INIT, ANY, CONST)
  {
        USE_OPLINE
 -      zval *assignment_value;
 -      zend_uint arg_num = opline->op1.num;
 -      zval **param = zend_vm_stack_get_arg(arg_num TSRMLS_CC);
 -      zval **var_ptr;
 +      uint32_t arg_num = opline->op1.num;
 +      zval *param;
  
        SAVE_OPLINE();
 -      if (param == NULL) {
 -              ALLOC_ZVAL(assignment_value);
 -              *assignment_value = *opline->op2.zv;
 -              if (IS_CONSTANT_TYPE(Z_TYPE_P(assignment_value))) {
 -                      Z_SET_REFCOUNT_P(assignment_value, 1);
 -                      zval_update_constant(&assignment_value, 0 TSRMLS_CC);
 -              } else if (Z_TYPE_P(assignment_value) == IS_ARRAY) {
 -                      HashTable *ht;
 -
 -                      ALLOC_HASHTABLE(ht);
 -                      zend_hash_init(ht, zend_hash_num_elements(Z_ARRVAL_P(assignment_value)), NULL, ZVAL_PTR_DTOR, 0);
 -                      zend_hash_copy(ht, Z_ARRVAL_P(assignment_value), (copy_ctor_func_t) zval_deep_copy, NULL, sizeof(zval *));
 -                      Z_ARRVAL_P(assignment_value) = ht;
 +      param = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->result.var TSRMLS_CC);
 +      if (arg_num > EX(num_args)) {
 +              ZVAL_COPY_VALUE(param, opline->op2.zv);
 +              if (Z_OPT_CONSTANT_P(param)) {
 +                      zval_update_constant(param, 0 TSRMLS_CC);
                } else {
 -                      zval_copy_ctor(assignment_value);
 +                      /* IS_CONST can't be IS_OBJECT, IS_RESOURCE or IS_REFERENCE */
 +                      if (UNEXPECTED(Z_OPT_COPYABLE_P(param))) {
 +                              zval_copy_ctor_func(param);
 +                      }
                }
 -              INIT_PZVAL(assignment_value);
 -      } else {
 -              assignment_value = *param;
 -              Z_ADDREF_P(assignment_value);
        }
  
 -      zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, assignment_value, opline->extended_value, opline->op2.zv TSRMLS_CC);
 -      var_ptr = _get_zval_ptr_ptr_cv_BP_VAR_W(execute_data, opline->result.var TSRMLS_CC);
 -      zval_ptr_dtor(var_ptr);
 -      *var_ptr = assignment_value;
 +      if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) {
-               zend_verify_arg_type(EX(func), arg_num, param TSRMLS_CC);
++              zend_verify_arg_type(EX(func), arg_num, param, opline->op2.zv TSRMLS_CC);
 +      }
  
        CHECK_EXCEPTION();
        ZEND_VM_NEXT_OPCODE();
@@@ -3570,27 -3456,13 +3570,27 @@@ ZEND_VM_HANDLER(164, ZEND_RECV_VARIADIC
  
        SAVE_OPLINE();
  
 -      var_ptr = _get_zval_ptr_ptr_cv_BP_VAR_W(execute_data, opline->result.var TSRMLS_CC);
 -      Z_DELREF_PP(var_ptr);
 -      MAKE_STD_ZVAL(params);
 -      *var_ptr = params;
 +      params = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->result.var TSRMLS_CC);
  
        if (arg_num <= arg_count) {
 +              zval *param;
 +
                array_init_size(params, arg_count - arg_num + 1);
-                               zend_verify_arg_type(EX(func), arg_num, param TSRMLS_CC);
 +              param = EX_VAR_NUM(EX(func)->op_array.last_var + EX(func)->op_array.T);
 +              if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) {
 +                      do {                    
++                              zend_verify_arg_type(EX(func), arg_num, param, NULL TSRMLS_CC);
 +                              zend_hash_next_index_insert_new(Z_ARRVAL_P(params), param);
 +                              if (Z_REFCOUNTED_P(param)) Z_ADDREF_P(param);
 +                              param++;
 +                      } while (++arg_num <= arg_count);
 +              } else {
 +                      do {
 +                              zend_hash_next_index_insert_new(Z_ARRVAL_P(params), param);
 +                              if (Z_REFCOUNTED_P(param)) Z_ADDREF_P(param);
 +                              param++;
 +                      } while (++arg_num <= arg_count);
 +              }
        } else {
                array_init(params);
        }
index 9ec7a8333476e2c24730a94657c0964baf674d10,20731b4ef5f65116f277781e2c3ac925148ed330..52104843702bc97ce307eb0b0bd90d7aa5ad91eb
@@@ -509,50 -499,49 +509,50 @@@ static int ZEND_FASTCALL  ZEND_DO_FCALL
                        }
                }
        }
 -      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);
 -                      if (UNEXPECTED(EG(exception) != NULL)) {
 -                              HANDLE_EXCEPTION();
 -                      }
 +      LOAD_OPLINE();
 +
 +      if (UNEXPECTED(fbc->type == ZEND_INTERNAL_FUNCTION)) {
 +              int should_change_scope = 0;
 +              zval *ret;
 +
 +              if (fbc->common.scope) {
 +                      should_change_scope = 1;
 +                      /* TODO: we don't set scope if we call an object method ??? */
 +                      /* See: ext/pdo_sqlite/tests/pdo_fetch_func_001.phpt */
 +#if 1
 +                      EG(scope) = object ? NULL : fbc->common.scope;
 +#else
 +                      EG(scope) = fbc->common.scope;
 +#endif
                } 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);
 +                      call->called_scope = EX(called_scope);
 +                      Z_OBJ(call->This) = Z_OBJ(EX(This));
                }
 -      }
 -
 -      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(call)->called_scope;
 -      }
  
 -      num_args = opline->extended_value + EX(call)->num_additional_args;
 -      if (EX(call)->num_additional_args) {
 -              EX(function_state).arguments = zend_vm_stack_push_args(num_args TSRMLS_CC);
 -      } else {
 -              EX(function_state).arguments = zend_vm_stack_top(TSRMLS_C);
 -              zend_vm_stack_push((void*)(zend_uintptr_t) num_args TSRMLS_CC);
 -      }
 -      LOAD_OPLINE();
 +              call->prev_execute_data = execute_data;
 +              EG(current_execute_data) = call;
  
 -      if (fbc->type == ZEND_INTERNAL_FUNCTION) {
                if (fbc->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) {
 -                      zend_uint i;
 -                      void **p = EX(function_state).arguments - num_args;
 +                      uint32_t i;
 +                      zval *p = ZEND_CALL_ARG(call, 1);
  
 -                      for (i = 0; i < num_args; ++i, ++p) {
 -                              zend_verify_arg_type(fbc, i + 1, (zval *) *p, 0, NULL TSRMLS_CC);
 +                      for (i = 0; i < call->num_args; ++i) {
-                               zend_verify_arg_type(fbc, i + 1, p TSRMLS_CC);
++                              zend_verify_arg_type(fbc, i + 1, p, NULL TSRMLS_CC);
 +                              p++;
 +                      }
 +                      if (UNEXPECTED(EG(exception) != NULL)) {
 +                              EG(current_execute_data) = call->prev_execute_data;
 +                              zend_vm_stack_free_args(call TSRMLS_CC);
 +                              zend_vm_stack_free_call_frame(call TSRMLS_CC);
 +                              if (RETURN_VALUE_USED(opline)) {
 +                                      ZVAL_UNDEF(EX_VAR(opline->result.var));
 +                              }
 +                              if (UNEXPECTED(should_change_scope)) {
 +                                      goto fcall_end_change_scope;
 +                              } else {
 +                                      goto fcall_end;
 +                              }
                        }
                }
  
@@@ -966,61 -894,86 +966,61 @@@ static int ZEND_FASTCALL  ZEND_SEND_ARR
        ZEND_VM_NEXT_OPCODE();
  }
  
 -static int ZEND_FASTCALL  ZEND_RECV_VARIADIC_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
 +static int ZEND_FASTCALL  ZEND_RECV_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
  {
        USE_OPLINE
 -      zend_uint arg_num = opline->op1.num;
 -      zend_uint arg_count = zend_vm_stack_get_args_count(TSRMLS_C);
 -      zval **var_ptr, *params;
 +      uint32_t arg_num = opline->op1.num;
  
        SAVE_OPLINE();
 +      if (UNEXPECTED(arg_num > EX(num_args))) {
 +              zend_verify_missing_arg(execute_data, arg_num TSRMLS_CC);
 +              CHECK_EXCEPTION();
 +      } else if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) {
 +              zval *param = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->result.var TSRMLS_CC);
  
-               zend_verify_arg_type(EX(func), arg_num, param TSRMLS_CC);
 -      var_ptr = _get_zval_ptr_ptr_cv_BP_VAR_W(execute_data, opline->result.var TSRMLS_CC);
 -      Z_DELREF_PP(var_ptr);
 -      MAKE_STD_ZVAL(params);
 -      *var_ptr = params;
 -
 -      if (arg_num <= arg_count) {
 -              array_init_size(params, arg_count - arg_num + 1);
 -      } else {
 -              array_init(params);
 -      }
 -
 -      for (; arg_num <= arg_count; ++arg_num) {
 -              zval **param = zend_vm_stack_get_arg(arg_num TSRMLS_CC);
 -              zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, *param, opline->extended_value, NULL TSRMLS_CC);
 -              zend_hash_next_index_insert(Z_ARRVAL_P(params), param, sizeof(zval *), NULL);
 -              Z_ADDREF_PP(param);
++              zend_verify_arg_type(EX(func), arg_num, param, NULL TSRMLS_CC);
 +              CHECK_EXCEPTION();
        }
  
 -      CHECK_EXCEPTION();
        ZEND_VM_NEXT_OPCODE();
  }
  
 -static int ZEND_FASTCALL  ZEND_NEW_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
 +static int ZEND_FASTCALL  ZEND_RECV_VARIADIC_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
  {
        USE_OPLINE
 -      zval *object_zval;
 -      zend_function *constructor;
 +      uint32_t arg_num = opline->op1.num;
 +      uint32_t arg_count = EX(num_args);
 +      zval *params;
  
        SAVE_OPLINE();
 -      if (UNEXPECTED((EX_T(opline->op1.var).class_entry->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) != 0)) {
 -              if (EX_T(opline->op1.var).class_entry->ce_flags & ZEND_ACC_INTERFACE) {
 -                      zend_error_noreturn(E_ERROR, "Cannot instantiate interface %s", EX_T(opline->op1.var).class_entry->name);
 -              } else if ((EX_T(opline->op1.var).class_entry->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) {
 -                      zend_error_noreturn(E_ERROR, "Cannot instantiate trait %s", EX_T(opline->op1.var).class_entry->name);
 -              } else {
 -                      zend_error_noreturn(E_ERROR, "Cannot instantiate abstract class %s", EX_T(opline->op1.var).class_entry->name);
 -              }
 -      }
 -      ALLOC_ZVAL(object_zval);
 -      object_init_ex(object_zval, EX_T(opline->op1.var).class_entry);
 -      INIT_PZVAL(object_zval);
  
 -      constructor = Z_OBJ_HT_P(object_zval)->get_constructor(object_zval TSRMLS_CC);
 +      params = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->result.var TSRMLS_CC);
  
 -      if (constructor == NULL) {
 -              if (RETURN_VALUE_USED(opline)) {
 -                      AI_SET_PTR(&EX_T(opline->result.var), object_zval);
 +      if (arg_num <= arg_count) {
 +              zval *param;
 +
 +              array_init_size(params, arg_count - arg_num + 1);
 +              param = EX_VAR_NUM(EX(func)->op_array.last_var + EX(func)->op_array.T);
 +              if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) {
 +                      do {
-                               zend_verify_arg_type(EX(func), arg_num, param TSRMLS_CC);
++                              zend_verify_arg_type(EX(func), arg_num, param, NULL TSRMLS_CC);
 +                              zend_hash_next_index_insert_new(Z_ARRVAL_P(params), param);
 +                              if (Z_REFCOUNTED_P(param)) Z_ADDREF_P(param);
 +                              param++;
 +                      } while (++arg_num <= arg_count);
                } else {
 -                      zval_ptr_dtor(&object_zval);
 +                      do {
 +                              zend_hash_next_index_insert_new(Z_ARRVAL_P(params), param);
 +                              if (Z_REFCOUNTED_P(param)) Z_ADDREF_P(param);
 +                              param++;
 +                      } while (++arg_num <= arg_count);
                }
 -              ZEND_VM_JMP(EX(op_array)->opcodes + opline->op2.opline_num);
        } else {
 -              call_slot *call = EX(call_slots) + opline->extended_value;
 -
 -              if (RETURN_VALUE_USED(opline)) {
 -                      PZVAL_LOCK(object_zval);
 -                      AI_SET_PTR(&EX_T(opline->result.var), object_zval);
 -              }
 -
 -              /* We are not handling overloaded classes right now */
 -              call->fbc = constructor;
 -              call->object = object_zval;
 -              call->called_scope = EX_T(opline->op1.var).class_entry;
 -              call->num_additional_args = 0;
 -              call->is_ctor_call = 1;
 -              call->is_ctor_result_used = RETURN_VALUE_USED(opline);
 -              EX(call) = call;
 -
 -              CHECK_EXCEPTION();
 -              ZEND_VM_NEXT_OPCODE();
 +              array_init(params);
        }
 +
 +      CHECK_EXCEPTION();
 +      ZEND_VM_NEXT_OPCODE();
  }
  
  static int ZEND_FASTCALL  ZEND_BEGIN_SILENCE_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
@@@ -1644,26 -1615,38 +1644,26 @@@ static int ZEND_FASTCALL  ZEND_INIT_FCA
  static int ZEND_FASTCALL  ZEND_RECV_INIT_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
  {
        USE_OPLINE
 -      zval *assignment_value;
 -      zend_uint arg_num = opline->op1.num;
 -      zval **param = zend_vm_stack_get_arg(arg_num TSRMLS_CC);
 -      zval **var_ptr;
 +      uint32_t arg_num = opline->op1.num;
 +      zval *param;
  
        SAVE_OPLINE();
 -      if (param == NULL) {
 -              ALLOC_ZVAL(assignment_value);
 -              *assignment_value = *opline->op2.zv;
 -              if (IS_CONSTANT_TYPE(Z_TYPE_P(assignment_value))) {
 -                      Z_SET_REFCOUNT_P(assignment_value, 1);
 -                      zval_update_constant(&assignment_value, 0 TSRMLS_CC);
 -              } else if (Z_TYPE_P(assignment_value) == IS_ARRAY) {
 -                      HashTable *ht;
 -
 -                      ALLOC_HASHTABLE(ht);
 -                      zend_hash_init(ht, zend_hash_num_elements(Z_ARRVAL_P(assignment_value)), NULL, ZVAL_PTR_DTOR, 0);
 -                      zend_hash_copy(ht, Z_ARRVAL_P(assignment_value), (copy_ctor_func_t) zval_deep_copy, NULL, sizeof(zval *));
 -                      Z_ARRVAL_P(assignment_value) = ht;
 +      param = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->result.var TSRMLS_CC);
 +      if (arg_num > EX(num_args)) {
 +              ZVAL_COPY_VALUE(param, opline->op2.zv);
 +              if (Z_OPT_CONSTANT_P(param)) {
 +                      zval_update_constant(param, 0 TSRMLS_CC);
                } else {
 -                      zval_copy_ctor(assignment_value);
 +                      /* IS_CONST can't be IS_OBJECT, IS_RESOURCE or IS_REFERENCE */
 +                      if (UNEXPECTED(Z_OPT_COPYABLE_P(param))) {
 +                              zval_copy_ctor_func(param);
 +                      }
                }
 -              INIT_PZVAL(assignment_value);
 -      } else {
 -              assignment_value = *param;
 -              Z_ADDREF_P(assignment_value);
        }
  
 -      zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, assignment_value, opline->extended_value, opline->op2.zv TSRMLS_CC);
 -      var_ptr = _get_zval_ptr_ptr_cv_BP_VAR_W(execute_data, opline->result.var TSRMLS_CC);
 -      zval_ptr_dtor(var_ptr);
 -      *var_ptr = assignment_value;
 +      if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) {
-               zend_verify_arg_type(EX(func), arg_num, param TSRMLS_CC);
++              zend_verify_arg_type(EX(func), arg_num, param, opline->op2.zv TSRMLS_CC);
 +      }
  
        CHECK_EXCEPTION();
        ZEND_VM_NEXT_OPCODE();