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