Commit:    aaabac2473e53327bf0587876799ca4aed6c9c19
Author:    Nikita Popov <ni...@php.net>         Thu, 27 Sep 2012 18:46:27 +0200
Parents:   da96aa848fc4845399d4d7a7c396fa31ffb9ffba 
592b232e834ed2698fa97ad4dd58e5ab21f257be
Branches:  master

Link:       
http://git.php.net/?p=php-src.git;a=commitdiff;h=aaabac2473e53327bf0587876799ca4aed6c9c19

Log:
Merge branch 'PHP-5.4'

Conflicts:
        Zend/zend_vm_def.h

Changed paths:
  MM  Zend/zend_vm_def.h
  MM  Zend/zend_vm_execute.h

diff --cc Zend/zend_vm_def.h
index e0fc1bf,9d475a6..ab5102f
--- a/Zend/zend_vm_def.h
+++ b/Zend/zend_vm_def.h
@@@ -2467,428 -2501,296 +2467,432 @@@ ZEND_VM_HANDLER(55, ZEND_ADD_STRING, TM
        ZEND_VM_NEXT_OPCODE();
  }
  
 -ZEND_VM_HELPER(zend_leave_helper, ANY, ANY)
 +ZEND_VM_HANDLER(56, ZEND_ADD_VAR, TMP|UNUSED, TMP|VAR|CV)
  {
 -      zend_bool nested;
 -      zend_op_array *op_array = EX(op_array);
 +      USE_OPLINE
 +      zend_free_op free_op2;
 +      zval *str = &EX_T(opline->result.var).tmp_var;
 +      zval *var;
 +      zval var_copy;
 +      int use_copy = 0;
  
 -      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++;
 -              }
 -      }
 +      SAVE_OPLINE();
 +      var = GET_OP2_ZVAL_PTR(BP_VAR_R);
  
 -      if ((op_array->fn_flags & ZEND_ACC_CLOSURE) && op_array->prototype) {
 -              zval_ptr_dtor((zval**)&op_array->prototype);
 +      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);
        }
  
 -      nested = EX(nested);
 +      if (Z_TYPE_P(var) != IS_STRING) {
 +              zend_make_printable_zval(var, &var_copy, &use_copy);
  
 -      zend_vm_stack_free(execute_data TSRMLS_CC);
 +              if (use_copy) {
 +                      var = &var_copy;
 +              }
 +      }
 +      add_string_to_string(str, str, var);
  
 -      if (nested) {
 -              execute_data = EG(current_execute_data);
 +      if (use_copy) {
 +              zval_dtor(var);
        }
 -      if (nested) {
 -              USE_OPLINE
 +      /* original comment, possibly problematic:
 +       * FREE_OP is missing intentionally here - we're always working on the 
same temporary variable
 +       * (Zeev):  I don't think it's problematic, we only use variables
 +       * which aren't affected by FREE_OP(Ts, )'s anyway, unless they're
 +       * string offsets or overloaded objects
 +       */
 +      FREE_OP2();
  
 -              LOAD_REGS();
 -              LOAD_OPLINE();
 -              if (UNEXPECTED(opline->opcode == ZEND_INCLUDE_OR_EVAL)) {
 +      CHECK_EXCEPTION();
 +      ZEND_VM_NEXT_OPCODE();
 +}
  
 -                      EX(function_state).function = (zend_function *) 
EX(op_array);
 -                      EX(function_state).arguments = NULL;
 -                      EX(object) = EX(current_object);
 +ZEND_VM_HANDLER(109, ZEND_FETCH_CLASS, ANY, CONST|TMP|VAR|UNUSED|CV)
 +{
 +      USE_OPLINE
  
 -                      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;
 +      SAVE_OPLINE();
 +      if (EG(exception)) {
 +              zend_exception_save(TSRMLS_C);
 +      }
 +      if (OP2_TYPE == IS_UNUSED) {
 +              EX_T(opline->result.var).class_entry = zend_fetch_class(NULL, 
0, opline->extended_value TSRMLS_CC);
 +              CHECK_EXCEPTION();
 +              ZEND_VM_NEXT_OPCODE();
 +      } else {
 +              zend_free_op free_op2;
 +              zval *class_name = GET_OP2_ZVAL_PTR(BP_VAR_R);
  
 -                                      ALLOC_ZVAL(retval);
 -                                      ZVAL_BOOL(retval, 1);
 -                                      INIT_PZVAL(retval);
 -                                      EX_T(opline->result.var).var.ptr = 
retval;
 -                              }
 +              if (OP2_TYPE == IS_CONST) {
 +                      if (CACHED_PTR(opline->op2.literal->cache_slot)) {
 +                              EX_T(opline->result.var).class_entry = 
CACHED_PTR(opline->op2.literal->cache_slot);
 +                      } else {
 +                              EX_T(opline->result.var).class_entry = 
zend_fetch_class_by_name(Z_STRVAL_P(class_name), Z_STRLEN_P(class_name), 
opline->op2.literal + 1, opline->extended_value TSRMLS_CC);
 +                              CACHE_PTR(opline->op2.literal->cache_slot, 
EX_T(opline->result.var).class_entry);
                        }
 -
 -                      ZEND_VM_INC_OPCODE();
 -                      ZEND_VM_LEAVE();
 +              } else if (Z_TYPE_P(class_name) == IS_OBJECT) {
 +                      EX_T(opline->result.var).class_entry = 
Z_OBJCE_P(class_name);
 +              } else if (Z_TYPE_P(class_name) == IS_STRING) {
 +                      EX_T(opline->result.var).class_entry = 
zend_fetch_class(Z_STRVAL_P(class_name), Z_STRLEN_P(class_name), 
opline->extended_value TSRMLS_CC);
                } else {
 +                      zend_error_noreturn(E_ERROR, "Class name must be a 
valid object or a string");
 +              }
  
 -                      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);
 +              FREE_OP2();
 +              CHECK_EXCEPTION();
 +              ZEND_VM_NEXT_OPCODE();
 +      }
 +}
  
 -                      EX(function_state).function = (zend_function *) 
EX(op_array);
 -                      EX(function_state).arguments = NULL;
 +ZEND_VM_HANDLER(112, ZEND_INIT_METHOD_CALL, TMP|VAR|UNUSED|CV, 
CONST|TMP|VAR|CV)
 +{
 +      USE_OPLINE
 +      zval *function_name;
 +      char *function_name_strval;
 +      int function_name_strlen;
 +      zend_free_op free_op1, free_op2;
  
 -                      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);
 +      SAVE_OPLINE();
 +      zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), 
EX(called_scope));
  
 -                      EX(object) = EX(current_object);
 -                      EX(called_scope) = DECODE_CTOR(EX(called_scope));
 +      function_name = GET_OP2_ZVAL_PTR(BP_VAR_R);
  
 -                      zend_vm_stack_clear_multiple(TSRMLS_C);
 +      if (OP2_TYPE != IS_CONST &&
 +          UNEXPECTED(Z_TYPE_P(function_name) != IS_STRING)) {
 +              zend_error_noreturn(E_ERROR, "Method name must be a string");
 +      }
  
 -                      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();
 +      function_name_strval = Z_STRVAL_P(function_name);
 +      function_name_strlen = Z_STRLEN_P(function_name);
 +
 +      EX(object) = GET_OP1_OBJ_ZVAL_PTR(BP_VAR_R);
 +
 +      if (EXPECTED(EX(object) != NULL) &&
 +          EXPECTED(Z_TYPE_P(EX(object)) == IS_OBJECT)) {
 +              EX(called_scope) = Z_OBJCE_P(EX(object));
 +
 +              if (OP2_TYPE != IS_CONST ||
 +                  (EX(fbc) = 
CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope))) == 
NULL) {
 +                  zval *object = EX(object);
 +
 +                      if (UNEXPECTED(Z_OBJ_HT_P(EX(object))->get_method == 
NULL)) {
 +                              zend_error_noreturn(E_ERROR, "Object does not 
support method calls");
                        }
  
 -                      ZEND_VM_INC_OPCODE();
 -                      ZEND_VM_LEAVE();
 +                      /* First, locate the function. */
 +                      EX(fbc) = 
Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, 
function_name_strlen, ((OP2_TYPE == IS_CONST) ? (opline->op2.literal + 1) : 
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)), function_name_strval);
 +                      }
 +                      if (OP2_TYPE == IS_CONST &&
 +                          EXPECTED(EX(fbc)->type <= ZEND_USER_FUNCTION) &&
 +                          EXPECTED((EX(fbc)->common.fn_flags & 
(ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) &&
 +                          EXPECTED(EX(object) == object)) {
 +                              
CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope), 
EX(fbc));
 +                      }
                }
 +      } else {
 +              zend_error_noreturn(E_ERROR, "Call to a member function %s() on 
a non-object", function_name_strval);
        }
 -      ZEND_VM_RETURN();
 +
 +      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;
 +              }
 +      }
 +
 +      FREE_OP2();
 +      FREE_OP1_IF_VAR();
 +
 +      CHECK_EXCEPTION();
 +      ZEND_VM_NEXT_OPCODE();
  }
  
 -ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY)
 +ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, CONST|VAR, 
CONST|TMP|VAR|UNUSED|CV)
  {
        USE_OPLINE
 -      zend_bool should_change_scope = 0;
 -      zend_function *fbc = EX(function_state).function;
 +      zval *function_name;
 +      zend_class_entry *ce;
  
        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)) {
 +      zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), 
EX(called_scope));
  
 -              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 (OP1_TYPE == IS_CONST) {
 +              /* no function found. try a static method in class */
 +              if (CACHED_PTR(opline->op1.literal->cache_slot)) {
 +                      ce = CACHED_PTR(opline->op1.literal->cache_slot);
                } 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);
 +                      ce = 
zend_fetch_class_by_name(Z_STRVAL_P(opline->op1.zv), 
Z_STRLEN_P(opline->op1.zv), opline->op1.literal + 1, opline->extended_value 
TSRMLS_CC);
 +                      if (UNEXPECTED(ce == NULL)) {
 +                              CHECK_EXCEPTION();
 +                              ZEND_VM_NEXT_OPCODE();
 +                      }
 +                      CACHE_PTR(opline->op1.literal->cache_slot, ce);
                }
 -      }
 +              EX(called_scope) = ce;
 +      } else {
 +              ce = EX_T(opline->op1.var).class_entry;
  
 -      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);
 +              if (opline->extended_value == ZEND_FETCH_CLASS_PARENT || 
opline->extended_value == ZEND_FETCH_CLASS_SELF) {
 +                      EX(called_scope) = EG(called_scope);
 +              } else {
 +                      EX(called_scope) = ce;
 +              }
        }
  
 -      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 (OP1_TYPE == IS_CONST &&
 +          OP2_TYPE == IS_CONST &&
 +          CACHED_PTR(opline->op2.literal->cache_slot)) {
 +              EX(fbc) = CACHED_PTR(opline->op2.literal->cache_slot);
 +      } else if (OP1_TYPE != IS_CONST &&
 +                 OP2_TYPE == IS_CONST &&
 +                 (EX(fbc) = 
CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce))) {
 +              /* do nothing */
 +      } else if (OP2_TYPE != IS_UNUSED) {
 +              char *function_name_strval = NULL;
 +              int function_name_strlen = 0;
 +              zend_free_op free_op2;
  
 -      if (fbc->type == ZEND_INTERNAL_FUNCTION) {
 -              temp_variable *ret = &EX_T(opline->result.var);
 +              if (OP2_TYPE == IS_CONST) {
 +                      function_name_strval = Z_STRVAL_P(opline->op2.zv);
 +                      function_name_strlen = Z_STRLEN_P(opline->op2.zv);
 +              } else {
 +                      function_name = GET_OP2_ZVAL_PTR(BP_VAR_R);
  
 -              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 (UNEXPECTED(Z_TYPE_P(function_name) != IS_STRING)) {
 +                              zend_error_noreturn(E_ERROR, "Function name 
must be a string");
 +                      } else {
 +                              function_name_strval = 
Z_STRVAL_P(function_name);
 +                              function_name_strlen = 
Z_STRLEN_P(function_name);
 +                      }
 +              }
  
 -              if (fbc->common.arg_info) {
 -                      zend_uint i=0;
 -                      zval **p = (zval**)EX(function_state).arguments;
 -                      ulong arg_count = opline->extended_value;
 +              if (function_name_strval) {
 +                      if (ce->get_static_method) {
 +                              EX(fbc) = ce->get_static_method(ce, 
function_name_strval, function_name_strlen TSRMLS_CC);
 +                      } else {
 +                              EX(fbc) = zend_std_get_static_method(ce, 
function_name_strval, function_name_strlen, ((OP2_TYPE == IS_CONST) ? 
(opline->op2.literal + 1) : NULL) TSRMLS_CC);
 +                      }
 +                      if (UNEXPECTED(EX(fbc) == NULL)) {
 +                              zend_error_noreturn(E_ERROR, "Call to undefined 
method %s::%s()", ce->name, function_name_strval);
 +                      }
 +                      if (OP2_TYPE == IS_CONST &&
 +                          EXPECTED(EX(fbc)->type <= ZEND_USER_FUNCTION) &&
 +                          EXPECTED((EX(fbc)->common.fn_flags & 
(ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) {
 +                              if (OP1_TYPE == IS_CONST) {
 +                                      
CACHE_PTR(opline->op2.literal->cache_slot, EX(fbc));
 +                              } else {
 +                                      
CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce, EX(fbc));
 +                              }
 +                      }
 +              }
 +              if (OP2_TYPE != IS_CONST) {
 +                      FREE_OP2();
 +              }
 +      } else {
 +              if (UNEXPECTED(ce->constructor == NULL)) {
 +                      zend_error_noreturn(E_ERROR, "Cannot call constructor");
 +              }
 +              if (EG(This) && Z_OBJCE_P(EG(This)) != 
ce->constructor->common.scope && (ce->constructor->common.fn_flags & 
ZEND_ACC_PRIVATE)) {
 +                      zend_error_noreturn(E_ERROR, "Cannot call private 
%s::__construct()", ce->name);
 +              }
 +              EX(fbc) = ce->constructor;
 +      }
  
 -                      while (arg_count>0) {
 -                              zend_verify_arg_type(fbc, ++i, *(p-arg_count), 
0 TSRMLS_CC);
 -                              arg_count--;
 +      if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
 +              EX(object) = NULL;
 +      } else {
 +              if (EG(This) &&
 +                  Z_OBJ_HT_P(EG(This))->get_class_entry &&
 +                  !instanceof_function(Z_OBJCE_P(EG(This)), ce TSRMLS_CC)) {
 +                  /* We are calling method of the other (incompatible) class,
 +                     but passing $this. This is done for compatibility with 
php-4. */
 +                      if (EX(fbc)->common.fn_flags & ZEND_ACC_ALLOW_STATIC) {
 +                              zend_error(E_STRICT, "Non-static method 
%s::%s() should not be called statically, assuming $this from incompatible 
context", EX(fbc)->common.scope->name, EX(fbc)->common.function_name);
 +                      } else {
 +                              /* 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, assuming $this from incompatible 
context", EX(fbc)->common.scope->name, EX(fbc)->common.function_name);
                        }
                }
 +              if ((EX(object) = EG(This))) {
 +                      Z_ADDREF_P(EX(object));
 +                      EX(called_scope) = Z_OBJCE_P(EX(object));
 +              }
 +      }
  
 -              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);
 +      CHECK_EXCEPTION();
 +      ZEND_VM_NEXT_OPCODE();
 +}
 +
 +ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMP|VAR|CV)
 +{
 +      USE_OPLINE
 +      zval *function_name;
 +      zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), 
EX(called_scope));
 +
 +      if (OP2_TYPE == IS_CONST) {
 +              function_name = (zval*)(opline->op2.literal+1);
 +              if (CACHED_PTR(opline->op2.literal->cache_slot)) {
 +                      EX(fbc) = CACHED_PTR(opline->op2.literal->cache_slot);
 +              } else if (UNEXPECTED(zend_hash_quick_find(EG(function_table), 
Z_STRVAL_P(function_name), Z_STRLEN_P(function_name)+1, 
Z_HASH_P(function_name), (void **) &EX(fbc)) == FAILURE)) {
 +                      SAVE_OPLINE();
 +                      zend_error_noreturn(E_ERROR, "Call to undefined 
function %s()", Z_STRVAL_P(opline->op2.zv));
                } else {
 -                      zend_execute_internal(EXECUTE_DATA, 
RETURN_VALUE_USED(opline) TSRMLS_CC);
 +                      CACHE_PTR(opline->op2.literal->cache_slot, EX(fbc));
                }
 +              EX(object) = NULL;
 +              /*CHECK_EXCEPTION();*/
 +              ZEND_VM_NEXT_OPCODE();
 +      } else {
 +              char *function_name_strval, *lcname;
 +              int function_name_strlen;
 +              zend_free_op free_op2;
  
 -              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);
 +              SAVE_OPLINE();
 +              function_name = GET_OP2_ZVAL_PTR(BP_VAR_R);
 +
 +              if (EXPECTED(Z_TYPE_P(function_name) == IS_STRING)) {
 +                      function_name_strval = Z_STRVAL_P(function_name);
 +                      function_name_strlen = Z_STRLEN_P(function_name);
 +                      if (function_name_strval[0] == '\\') {
 +                          function_name_strlen -= 1;
 +                              lcname = 
zend_str_tolower_dup(function_name_strval + 1, function_name_strlen);
 +                      } else {
 +                              lcname = 
zend_str_tolower_dup(function_name_strval, function_name_strlen);
 +                      }
 +                      if (UNEXPECTED(zend_hash_find(EG(function_table), 
lcname, function_name_strlen+1, (void **) &EX(fbc)) == FAILURE)) {
 +                              zend_error_noreturn(E_ERROR, "Call to undefined 
function %s()", function_name_strval);
 +                      }
 +                      efree(lcname);
 +                      FREE_OP2();
 +                      EX(object) = NULL;
 +                      CHECK_EXCEPTION();
 +                      ZEND_VM_NEXT_OPCODE();
 +              } else if (OP2_TYPE != IS_CONST && OP2_TYPE != IS_TMP_VAR &&
 +                  EXPECTED(Z_TYPE_P(function_name) == IS_OBJECT) &&
 +                      Z_OBJ_HANDLER_P(function_name, get_closure) &&
 +                      Z_OBJ_HANDLER_P(function_name, 
get_closure)(function_name, &EX(called_scope), &EX(fbc), &EX(object) TSRMLS_CC) 
== SUCCESS) {
 +                      if (EX(object)) {
 +                              Z_ADDREF_P(EX(object));
 +                      }
 +                      if (OP2_TYPE == IS_VAR && OP2_FREE &&
 +                          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;
  
 -                      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 (!obj || !method) {
++                              zend_error_noreturn(E_ERROR, "Array callback 
has to contain indices 0 and 1");
+                       }
 -              } 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(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");
                        }
 -              }
 -              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 (Z_TYPE_PP(method) != IS_STRING) {
 +                              zend_error_noreturn(E_ERROR, "Second array 
member is not a valid method");
 +                      }
  
 -              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();
  }
-- 
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to