diff options
| author | Dmitry Stogov <dmitry@zend.com> | 2015-02-24 22:29:47 +0300 |
|---|---|---|
| committer | Dmitry Stogov <dmitry@zend.com> | 2015-02-24 22:29:47 +0300 |
| commit | dcb96c2e037e5198932385b573baea9a9dbf3252 (patch) | |
| tree | b86aea3224a3db57fcd9f80b813122f7025aa001 | |
| parent | bdf1430eeba10d444274642572b9e1ac84013080 (diff) | |
| download | php-git-dcb96c2e037e5198932385b573baea9a9dbf3252.tar.gz | |
Split INIT_FCALL_BY_NAME inti INIT_FCALL_BY_NAME(CONST+STRING) and INIT_DYNAMIC_CALL(CONST-STRING|TMPVAR|CV)
| -rw-r--r-- | Zend/zend_compile.c | 5 | ||||
| -rw-r--r-- | Zend/zend_vm_def.h | 244 | ||||
| -rw-r--r-- | Zend/zend_vm_execute.h | 754 | ||||
| -rw-r--r-- | Zend/zend_vm_opcodes.c | 2 | ||||
| -rw-r--r-- | Zend/zend_vm_opcodes.h | 1 | ||||
| -rw-r--r-- | ext/opcache/Optimizer/compact_literals.c | 4 | ||||
| -rw-r--r-- | ext/opcache/Optimizer/optimize_func_calls.c | 1 | ||||
| -rw-r--r-- | ext/opcache/Optimizer/zend_optimizer.c | 7 |
8 files changed, 493 insertions, 525 deletions
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index e7177c7cd0..f22f1c67b7 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -2672,16 +2672,17 @@ void zend_compile_ns_call(znode *result, znode *name_node, zend_ast *args_ast) / void zend_compile_dynamic_call(znode *result, znode *name_node, zend_ast *args_ast) /* {{{ */ { zend_op *opline = get_next_op(CG(active_op_array)); - opline->opcode = ZEND_INIT_FCALL_BY_NAME; - SET_UNUSED(opline->op1); if (name_node->op_type == IS_CONST && Z_TYPE(name_node->u.constant) == IS_STRING) { + opline->opcode = ZEND_INIT_FCALL_BY_NAME; opline->op2_type = IS_CONST; opline->op2.constant = zend_add_func_name_literal(CG(active_op_array), Z_STR(name_node->u.constant)); zend_alloc_cache_slot(opline->op2.constant); } else { + opline->opcode = ZEND_INIT_DYNAMIC_CALL; SET_NODE(opline->op2, name_node); } + SET_UNUSED(opline->op1); zend_compile_call_common(result, args_ast, NULL); } diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index ed7814d8b8..c6372ea557 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -2347,6 +2347,7 @@ ZEND_VM_HANDLER(112, ZEND_INIT_METHOD_CALL, TMPVAR|UNUSED|CV, CONST|TMPVAR|CV) if (opline->opcode == ZEND_INIT_FCALL || opline->opcode == ZEND_INIT_FCALL_BY_NAME || opline->opcode == ZEND_INIT_NS_FCALL_BY_NAME || + opline->opcode == ZEND_INIT_DYNAMIC_CALL || opline->opcode == ZEND_INIT_METHOD_CALL || opline->opcode == ZEND_INIT_STATIC_METHOD_CALL || opline->opcode == ZEND_INIT_USER_CALL || @@ -2534,155 +2535,154 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, CONST|VAR, CONST|TMPVAR|UNUSE ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMPVAR|CV) +ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST) { USE_OPLINE zend_function *fbc; zval *function_name, *func; - if (OP2_TYPE == IS_CONST) { - if (EXPECTED(CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2))))) { - fbc = CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2))); + if (EXPECTED(CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2))))) { + fbc = CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2))); + } else { + function_name = (zval*)(EX_CONSTANT(opline->op2)+1); + if (UNEXPECTED((func = zend_hash_find(EG(function_table), Z_STR_P(function_name))) == NULL)) { + SAVE_OPLINE(); + zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(EX_CONSTANT(opline->op2))); } else { - if (UNEXPECTED(Z_TYPE_P(EX_CONSTANT(opline->op2)) != IS_STRING)) { - goto init_fcall_complex; - } - function_name = (zval*)(EX_CONSTANT(opline->op2)+1); - if (UNEXPECTED((func = zend_hash_find(EG(function_table), Z_STR_P(function_name))) == NULL)) { - SAVE_OPLINE(); - zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(EX_CONSTANT(opline->op2))); - } else { - fbc = Z_FUNC_P(func); - CACHE_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)), fbc); - } + fbc = Z_FUNC_P(func); + CACHE_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)), fbc); } - EX(call) = zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION, - fbc, opline->extended_value, NULL, NULL, EX(call)); + } + EX(call) = zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION, + fbc, opline->extended_value, NULL, NULL, EX(call)); - /*CHECK_EXCEPTION();*/ - ZEND_VM_NEXT_OPCODE(); - } else { - zend_string *lcname; - zend_free_op free_op2; - zend_class_entry *called_scope; - zend_object *object; + /*CHECK_EXCEPTION();*/ + ZEND_VM_NEXT_OPCODE(); +} -init_fcall_complex: - SAVE_OPLINE(); - function_name = GET_OP2_ZVAL_PTR(BP_VAR_R); +ZEND_VM_HANDLER(128, ZEND_INIT_DYNAMIC_CALL, ANY, CONST|TMPVAR|CV) +{ + USE_OPLINE + zend_function *fbc; + zval *function_name, *func; + zend_string *lcname; + zend_free_op free_op2; + zend_class_entry *called_scope; + zend_object *object; + + SAVE_OPLINE(); + function_name = GET_OP2_ZVAL_PTR(BP_VAR_R); ZEND_VM_C_LABEL(try_function_name): - if (OP2_TYPE != IS_CONST && EXPECTED(Z_TYPE_P(function_name) == IS_STRING)) { - if (Z_STRVAL_P(function_name)[0] == '\\') { - lcname = zend_string_alloc(Z_STRLEN_P(function_name) - 1, 0); - zend_str_tolower_copy(lcname->val, Z_STRVAL_P(function_name) + 1, Z_STRLEN_P(function_name) - 1); - } else { - lcname = zend_string_tolower(Z_STR_P(function_name)); - } - if (UNEXPECTED((func = zend_hash_find(EG(function_table), lcname)) == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(function_name)); - } - zend_string_release(lcname); + if (OP2_TYPE != IS_CONST && EXPECTED(Z_TYPE_P(function_name) == IS_STRING)) { + if (Z_STRVAL_P(function_name)[0] == '\\') { + lcname = zend_string_alloc(Z_STRLEN_P(function_name) - 1, 0); + zend_str_tolower_copy(lcname->val, Z_STRVAL_P(function_name) + 1, Z_STRLEN_P(function_name) - 1); + } else { + lcname = zend_string_tolower(Z_STR_P(function_name)); + } + if (UNEXPECTED((func = zend_hash_find(EG(function_table), lcname)) == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(function_name)); + } + zend_string_release(lcname); + FREE_OP2(); + + fbc = Z_FUNC_P(func); + called_scope = NULL; + object = NULL; + } else if (OP2_TYPE != IS_CONST && + 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, &called_scope, &fbc, &object) == SUCCESS) { + if (object) { + GC_REFCOUNT(object)++; + } + if (OP2_TYPE == IS_VAR && (fbc->common.fn_flags & ZEND_ACC_CLOSURE)) { + /* Delay closure destruction until its invocation */ + fbc->common.prototype = (zend_function*)Z_OBJ_P(free_op2); + } else if (OP2_TYPE == IS_CV) { FREE_OP2(); + } + } else if (EXPECTED(Z_TYPE_P(function_name) == IS_ARRAY) && + zend_hash_num_elements(Z_ARRVAL_P(function_name)) == 2) { + zval *obj; + zval *method; + obj = zend_hash_index_find(Z_ARRVAL_P(function_name), 0); + method = zend_hash_index_find(Z_ARRVAL_P(function_name), 1); - fbc = Z_FUNC_P(func); - called_scope = NULL; - object = NULL; - } else if (OP2_TYPE != IS_CONST && - 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, &called_scope, &fbc, &object) == SUCCESS) { - if (object) { - GC_REFCOUNT(object)++; - } - if (OP2_TYPE == IS_VAR && (fbc->common.fn_flags & ZEND_ACC_CLOSURE)) { - /* Delay closure destruction until its invocation */ - fbc->common.prototype = (zend_function*)Z_OBJ_P(free_op2); - } else if (OP2_TYPE == IS_CV) { - FREE_OP2(); - } - } else if (EXPECTED(Z_TYPE_P(function_name) == IS_ARRAY) && - zend_hash_num_elements(Z_ARRVAL_P(function_name)) == 2) { - zval *obj; - zval *method; + if (!obj || !method) { + zend_error_noreturn(E_ERROR, "Array callback has to contain indices 0 and 1"); + } - obj = zend_hash_index_find(Z_ARRVAL_P(function_name), 0); - method = zend_hash_index_find(Z_ARRVAL_P(function_name), 1); + ZVAL_DEREF(obj); + if (Z_TYPE_P(obj) != IS_STRING && Z_TYPE_P(obj) != IS_OBJECT) { + zend_error_noreturn(E_ERROR, "First array member is not a valid class name or object"); + } - if (!obj || !method) { - zend_error_noreturn(E_ERROR, "Array callback has to contain indices 0 and 1"); - } + ZVAL_DEREF(method); + if (Z_TYPE_P(method) != IS_STRING) { + zend_error_noreturn(E_ERROR, "Second array member is not a valid method"); + } - ZVAL_DEREF(obj); - if (Z_TYPE_P(obj) != IS_STRING && Z_TYPE_P(obj) != IS_OBJECT) { - zend_error_noreturn(E_ERROR, "First array member is not a valid class name or object"); + if (Z_TYPE_P(obj) == IS_STRING) { + object = NULL; + called_scope = zend_fetch_class_by_name(Z_STR_P(obj), NULL, 0); + if (UNEXPECTED(called_scope == NULL)) { + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); } - ZVAL_DEREF(method); - if (Z_TYPE_P(method) != IS_STRING) { - zend_error_noreturn(E_ERROR, "Second array member is not a valid method"); + if (called_scope->get_static_method) { + fbc = called_scope->get_static_method(called_scope, Z_STR_P(method)); + } else { + fbc = zend_std_get_static_method(called_scope, Z_STR_P(method), NULL); } - - if (Z_TYPE_P(obj) == IS_STRING) { - object = NULL; - called_scope = zend_fetch_class_by_name(Z_STR_P(obj), NULL, 0); - if (UNEXPECTED(called_scope == NULL)) { - CHECK_EXCEPTION(); - ZEND_VM_NEXT_OPCODE(); - } - - if (called_scope->get_static_method) { - fbc = called_scope->get_static_method(called_scope, Z_STR_P(method)); - } else { - fbc = zend_std_get_static_method(called_scope, Z_STR_P(method), NULL); - } - 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, + 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); - 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 */ + zend_error_noreturn( + E_ERROR, + "Non-static method %s::%s() cannot be called statically", + fbc->common.scope->name->val, fbc->common.function_name->val); } } - FREE_OP2(); - } else if ((OP2_TYPE & (IS_VAR|IS_CV)) && Z_TYPE_P(function_name) == IS_REFERENCE) { - function_name = Z_REFVAL_P(function_name); - ZEND_VM_C_GOTO(try_function_name); } else { - if (UNEXPECTED(EG(exception) != NULL)) { - HANDLE_EXCEPTION(); + 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); + if (UNEXPECTED(fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", object->ce->name->val, Z_STRVAL_P(method)); } - zend_error_noreturn(E_ERROR, "Function name must be a string"); - ZEND_VM_CONTINUE(); /* Never reached */ - } - EX(call) = zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION, - fbc, opline->extended_value, called_scope, object, EX(call)); - CHECK_EXCEPTION(); - ZEND_VM_NEXT_OPCODE(); + if ((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + object = NULL; + } else { + GC_REFCOUNT(object)++; /* For $this pointer */ + } + } + FREE_OP2(); + } else if ((OP2_TYPE & (IS_VAR|IS_CV)) && Z_TYPE_P(function_name) == IS_REFERENCE) { + function_name = Z_REFVAL_P(function_name); + ZEND_VM_C_GOTO(try_function_name); + } 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(ZEND_CALL_NESTED_FUNCTION, + fbc, opline->extended_value, called_scope, object, EX(call)); + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(118, ZEND_INIT_USER_CALL, CONST, CONST|TMPVAR|CV) @@ -5970,6 +5970,7 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY) case ZEND_INIT_FCALL: case ZEND_INIT_FCALL_BY_NAME: case ZEND_INIT_NS_FCALL_BY_NAME: + case ZEND_INIT_DYNAMIC_CALL: case ZEND_INIT_USER_CALL: case ZEND_INIT_METHOD_CALL: case ZEND_INIT_STATIC_METHOD_CALL: @@ -6015,6 +6016,7 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY) case ZEND_INIT_FCALL: case ZEND_INIT_FCALL_BY_NAME: case ZEND_INIT_NS_FCALL_BY_NAME: + case ZEND_INIT_DYNAMIC_CALL: case ZEND_INIT_USER_CALL: case ZEND_INIT_METHOD_CALL: case ZEND_INIT_STATIC_METHOD_CALL: diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 31462bc07c..cc1df6ab90 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -1260,6 +1260,7 @@ static int ZEND_FASTCALL ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(ZEND_OPCODE_HANDLER case ZEND_INIT_FCALL: case ZEND_INIT_FCALL_BY_NAME: case ZEND_INIT_NS_FCALL_BY_NAME: + case ZEND_INIT_DYNAMIC_CALL: case ZEND_INIT_USER_CALL: case ZEND_INIT_METHOD_CALL: case ZEND_INIT_STATIC_METHOD_CALL: @@ -1305,6 +1306,7 @@ static int ZEND_FASTCALL ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(ZEND_OPCODE_HANDLER case ZEND_INIT_FCALL: case ZEND_INIT_FCALL_BY_NAME: case ZEND_INIT_NS_FCALL_BY_NAME: + case ZEND_INIT_DYNAMIC_CALL: case ZEND_INIT_USER_CALL: case ZEND_INIT_METHOD_CALL: case ZEND_INIT_STATIC_METHOD_CALL: @@ -1559,148 +1561,147 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPCODE zend_function *fbc; zval *function_name, *func; - if (IS_CONST == IS_CONST) { - if (EXPECTED(CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2))))) { - fbc = CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2))); + if (EXPECTED(CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2))))) { + fbc = CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2))); + } else { + function_name = (zval*)(EX_CONSTANT(opline->op2)+1); + if (UNEXPECTED((func = zend_hash_find(EG(function_table), Z_STR_P(function_name))) == NULL)) { + SAVE_OPLINE(); + zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(EX_CONSTANT(opline->op2))); } else { - if (UNEXPECTED(Z_TYPE_P(EX_CONSTANT(opline->op2)) != IS_STRING)) { - goto init_fcall_complex; - } - function_name = (zval*)(EX_CONSTANT(opline->op2)+1); - if (UNEXPECTED((func = zend_hash_find(EG(function_table), Z_STR_P(function_name))) == NULL)) { - SAVE_OPLINE(); - zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(EX_CONSTANT(opline->op2))); - } else { - fbc = Z_FUNC_P(func); - CACHE_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)), fbc); - } + fbc = Z_FUNC_P(func); + CACHE_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)), fbc); } - EX(call) = zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION, - fbc, opline->extended_value, NULL, NULL, EX(call)); + } + EX(call) = zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION, + fbc, opline->extended_value, NULL, NULL, EX(call)); - /*CHECK_EXCEPTION();*/ - ZEND_VM_NEXT_OPCODE(); - } else { - zend_string *lcname; - zend_free_op free_op2; - zend_class_entry *called_scope; - zend_object *object; + /*CHECK_EXCEPTION();*/ + ZEND_VM_NEXT_OPCODE(); +} -init_fcall_complex: - SAVE_OPLINE(); - function_name = EX_CONSTANT(opline->op2); +static int ZEND_FASTCALL ZEND_INIT_DYNAMIC_CALL_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_function *fbc; + zval *function_name, *func; + zend_string *lcname; + zend_free_op free_op2; + zend_class_entry *called_scope; + zend_object *object; + + SAVE_OPLINE(); + function_name = EX_CONSTANT(opline->op2); try_function_name: - if (IS_CONST != IS_CONST && EXPECTED(Z_TYPE_P(function_name) == IS_STRING)) { - if (Z_STRVAL_P(function_name)[0] == '\\') { - lcname = zend_string_alloc(Z_STRLEN_P(function_name) - 1, 0); - zend_str_tolower_copy(lcname->val, Z_STRVAL_P(function_name) + 1, Z_STRLEN_P(function_name) - 1); - } else { - lcname = zend_string_tolower(Z_STR_P(function_name)); - } - if (UNEXPECTED((func = zend_hash_find(EG(function_table), lcname)) == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(function_name)); - } - zend_string_release(lcname); + if (IS_CONST != IS_CONST && EXPECTED(Z_TYPE_P(function_name) == IS_STRING)) { + if (Z_STRVAL_P(function_name)[0] == '\\') { + lcname = zend_string_alloc(Z_STRLEN_P(function_name) - 1, 0); + zend_str_tolower_copy(lcname->val, Z_STRVAL_P(function_name) + 1, Z_STRLEN_P(function_name) - 1); + } else { + lcname = zend_string_tolower(Z_STR_P(function_name)); + } + if (UNEXPECTED((func = zend_hash_find(EG(function_table), lcname)) == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(function_name)); + } + zend_string_release(lcname); - fbc = Z_FUNC_P(func); - called_scope = NULL; - object = NULL; - } else if (IS_CONST != IS_CONST && - 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, &called_scope, &fbc, &object) == SUCCESS) { - if (object) { - GC_REFCOUNT(object)++; - } - if (IS_CONST == IS_VAR && (fbc->common.fn_flags & ZEND_ACC_CLOSURE)) { - /* Delay closure destruction until its invocation */ - fbc->common.prototype = (zend_function*)Z_OBJ_P(free_op2); - } else if (IS_CONST == IS_CV) { + fbc = Z_FUNC_P(func); + called_scope = NULL; + object = NULL; + } else if (IS_CONST != IS_CONST && + 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, &called_scope, &fbc, &object) == SUCCESS) { + if (object) { + GC_REFCOUNT(object)++; + } + if (IS_CONST == IS_VAR && (fbc->common.fn_flags & ZEND_ACC_CLOSURE)) { + /* Delay closure destruction until its invocation */ + fbc->common.prototype = (zend_function*)Z_OBJ_P(free_op2); + } else if (IS_CONST == IS_CV) { - } - } else if (EXPECTED(Z_TYPE_P(function_name) == IS_ARRAY) && - zend_hash_num_elements(Z_ARRVAL_P(function_name)) == 2) { - zval *obj; - zval *method; + } + } else if (EXPECTED(Z_TYPE_P(function_name) == IS_ARRAY) && + zend_hash_num_elements(Z_ARRVAL_P(function_name)) == 2) { + zval *obj; + zval *method; + obj = zend_hash_index_find(Z_ARRVAL_P(function_name), 0); + method = zend_hash_index_find(Z_ARRVAL_P(function_name), 1); - obj = zend_hash_index_find(Z_ARRVAL_P(function_name), 0); - method = zend_hash_index_find(Z_ARRVAL_P(function_name), 1); + if (!obj || !method) { + zend_error_noreturn(E_ERROR, "Array callback has to contain indices 0 and 1"); + } - if (!obj || !method) { - zend_error_noreturn(E_ERROR, "Array callback has to contain indices 0 and 1"); - } + ZVAL_DEREF(obj); + if (Z_TYPE_P(obj) != IS_STRING && Z_TYPE_P(obj) != IS_OBJECT) { + zend_error_noreturn(E_ERROR, "First array member is not a valid class name or object"); + } - ZVAL_DEREF(obj); - if (Z_TYPE_P(obj) != IS_STRING && Z_TYPE_P(obj) != IS_OBJECT) { - zend_error_noreturn(E_ERROR, "First array member is not a valid class name or object"); - } + ZVAL_DEREF(method); + if (Z_TYPE_P(method) != IS_STRING) { + zend_error_noreturn(E_ERROR, "Second array member is not a valid method"); + } - ZVAL_DEREF(method); - if (Z_TYPE_P(method) != IS_STRING) { - zend_error_noreturn(E_ERROR, "Second array member is not a valid method"); + if (Z_TYPE_P(obj) == IS_STRING) { + object = NULL; + called_scope = zend_fetch_class_by_name(Z_STR_P(obj), NULL, 0); + if (UNEXPECTED(called_scope == NULL)) { + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); } - if (Z_TYPE_P(obj) == IS_STRING) { - object = NULL; - called_scope = zend_fetch_class_by_name(Z_STR_P(obj), NULL, 0); - if (UNEXPECTED(called_scope == NULL)) { - CHECK_EXCEPTION(); - ZEND_VM_NEXT_OPCODE(); - } - - if (called_scope->get_static_method) { - fbc = called_scope->get_static_method(called_scope, Z_STR_P(method)); - } else { - fbc = zend_std_get_static_method(called_scope, Z_STR_P(method), NULL); - } - 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, + if (called_scope->get_static_method) { + fbc = called_scope->get_static_method(called_scope, Z_STR_P(method)); + } else { + fbc = zend_std_get_static_method(called_scope, Z_STR_P(method), NULL); + } + 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); - 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 */ + 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 if ((IS_CONST & (IS_VAR|IS_CV)) && Z_TYPE_P(function_name) == IS_REFERENCE) { - function_name = Z_REFVAL_P(function_name); - goto try_function_name; } else { - if (UNEXPECTED(EG(exception) != NULL)) { - HANDLE_EXCEPTION(); + 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); + 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 */ } - zend_error_noreturn(E_ERROR, "Function name must be a string"); - ZEND_VM_CONTINUE(); /* Never reached */ } - EX(call) = zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION, - fbc, opline->extended_value, called_scope, object, EX(call)); - CHECK_EXCEPTION(); - ZEND_VM_NEXT_OPCODE(); + } else if ((IS_CONST & (IS_VAR|IS_CV)) && Z_TYPE_P(function_name) == IS_REFERENCE) { + function_name = Z_REFVAL_P(function_name); + goto try_function_name; + } 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(ZEND_CALL_NESTED_FUNCTION, + fbc, opline->extended_value, called_scope, object, EX(call)); + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); } static int ZEND_FASTCALL ZEND_INIT_NS_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -1949,154 +1950,128 @@ try_class_name: } } -static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +static int ZEND_FASTCALL ZEND_INIT_DYNAMIC_CALL_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE zend_function *fbc; zval *function_name, *func; + zend_string *lcname; + zend_free_op free_op2; + zend_class_entry *called_scope; + zend_object *object; + + SAVE_OPLINE(); + function_name = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var); - if (IS_CV == IS_CONST) { - if (EXPECTED(CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2))))) { - fbc = CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2))); +try_function_name: + if (IS_CV != IS_CONST && EXPECTED(Z_TYPE_P(function_name) == IS_STRING)) { + if (Z_STRVAL_P(function_name)[0] == '\\') { + lcname = zend_string_alloc(Z_STRLEN_P(function_name) - 1, 0); + zend_str_tolower_copy(lcname->val, Z_STRVAL_P(function_name) + 1, Z_STRLEN_P(function_name) - 1); } else { - if (UNEXPECTED(Z_TYPE_P(EX_CONSTANT(opline->op2)) != IS_STRING)) { - goto init_fcall_complex; - } - function_name = (zval*)(EX_CONSTANT(opline->op2)+1); - if (UNEXPECTED((func = zend_hash_find(EG(function_table), Z_STR_P(function_name))) == NULL)) { - SAVE_OPLINE(); - zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(EX_CONSTANT(opline->op2))); - } else { - fbc = Z_FUNC_P(func); - CACHE_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)), fbc); - } + lcname = zend_string_tolower(Z_STR_P(function_name)); } - EX(call) = zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION, - fbc, opline->extended_value, NULL, NULL, EX(call)); - - /*CHECK_EXCEPTION();*/ - ZEND_VM_NEXT_OPCODE(); - } else { - zend_string *lcname; - zend_free_op free_op2; - zend_class_entry *called_scope; - zend_object *object; + if (UNEXPECTED((func = zend_hash_find(EG(function_table), lcname)) == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(function_name)); + } + zend_string_release(lcname); -init_fcall_complex: - SAVE_OPLINE(); - function_name = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var); + fbc = Z_FUNC_P(func); + called_scope = NULL; + object = NULL; + } else if (IS_CV != IS_CONST && + 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, &called_scope, &fbc, &object) == SUCCESS) { + if (object) { + GC_REFCOUNT(object)++; + } + if (IS_CV == IS_VAR && (fbc->common.fn_flags & ZEND_ACC_CLOSURE)) { + /* Delay closure destruction until its invocation */ + fbc->common.prototype = (zend_function*)Z_OBJ_P(free_op2); + } else if (IS_CV == IS_CV) { -try_function_name: - if (IS_CV != IS_CONST && EXPECTED(Z_TYPE_P(function_name) == IS_STRING)) { - if (Z_STRVAL_P(function_name)[0] == '\\') { - lcname = zend_string_alloc(Z_STRLEN_P(function_name) - 1, 0); - zend_str_tolower_copy(lcname->val, Z_STRVAL_P(function_name) + 1, Z_STRLEN_P(function_name) - 1); - } else { - lcname = zend_string_tolower(Z_STR_P(function_name)); - } - if (UNEXPECTED((func = zend_hash_find(EG(function_table), lcname)) == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(function_name)); - } - zend_string_release(lcname); + } + } else if (EXPECTED(Z_TYPE_P(function_name) == IS_ARRAY) && + zend_hash_num_elements(Z_ARRVAL_P(function_name)) == 2) { + zval *obj; + zval *method; + obj = zend_hash_index_find(Z_ARRVAL_P(function_name), 0); + method = zend_hash_index_find(Z_ARRVAL_P(function_name), 1); - fbc = Z_FUNC_P(func); - called_scope = NULL; - object = NULL; - } else if (IS_CV != IS_CONST && - 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, &called_scope, &fbc, &object) == SUCCESS) { - if (object) { - GC_REFCOUNT(object)++; - } - if (IS_CV == IS_VAR && (fbc->common.fn_flags & ZEND_ACC_CLOSURE)) { - /* Delay closure destruction until its invocation */ - fbc->common.prototype = (zend_function*)Z_OBJ_P(free_op2); - } else if (IS_CV == IS_CV) { + if (!obj || !method) { + zend_error_noreturn(E_ERROR, "Array callback has to contain indices 0 and 1"); + } - } - } else if (EXPECTED(Z_TYPE_P(function_name) == IS_ARRAY) && - zend_hash_num_elements(Z_ARRVAL_P(function_name)) == 2) { - zval *obj; - zval *method; + ZVAL_DEREF(obj); + if (Z_TYPE_P(obj) != IS_STRING && Z_TYPE_P(obj) != IS_OBJECT) { + zend_error_noreturn(E_ERROR, "First array member is not a valid class name or object"); + } - obj = zend_hash_index_find(Z_ARRVAL_P(function_name), 0); - method = zend_hash_index_find(Z_ARRVAL_P(function_name), 1); + ZVAL_DEREF(method); + if (Z_TYPE_P(method) != IS_STRING) { + zend_error_noreturn(E_ERROR, "Second array member is not a valid method"); + } - if (!obj || !method) { - zend_error_noreturn(E_ERROR, "Array callback has to contain indices 0 and 1"); + if (Z_TYPE_P(obj) == IS_STRING) { + object = NULL; + called_scope = zend_fetch_class_by_name(Z_STR_P(obj), NULL, 0); + if (UNEXPECTED(called_scope == NULL)) { + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); } - ZVAL_DEREF(obj); - if (Z_TYPE_P(obj) != IS_STRING && Z_TYPE_P(obj) != IS_OBJECT) { - zend_error_noreturn(E_ERROR, "First array member is not a valid class name or object"); + if (called_scope->get_static_method) { + fbc = called_scope->get_static_method(called_scope, Z_STR_P(method)); + } else { + fbc = zend_std_get_static_method(called_scope, Z_STR_P(method), NULL); } - - ZVAL_DEREF(method); - if (Z_TYPE_P(method) != IS_STRING) { - zend_error_noreturn(E_ERROR, "Second array member is not a valid method"); + if (UNEXPECTED(fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", called_scope->name->val, Z_STRVAL_P(method)); } - - if (Z_TYPE_P(obj) == IS_STRING) { - object = NULL; - called_scope = zend_fetch_class_by_name(Z_STR_P(obj), NULL, 0); - if (UNEXPECTED(called_scope == NULL)) { - CHECK_EXCEPTION(); - ZEND_VM_NEXT_OPCODE(); - } - - if (called_scope->get_static_method) { - fbc = called_scope->get_static_method(called_scope, Z_STR_P(method)); - } else { - fbc = zend_std_get_static_method(called_scope, Z_STR_P(method), NULL); - } - 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, + 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); - 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 */ + 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 if ((IS_CV & (IS_VAR|IS_CV)) && Z_TYPE_P(function_name) == IS_REFERENCE) { - function_name = Z_REFVAL_P(function_name); - goto try_function_name; } else { - if (UNEXPECTED(EG(exception) != NULL)) { - HANDLE_EXCEPTION(); + 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); + 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 */ } - zend_error_noreturn(E_ERROR, "Function name must be a string"); - ZEND_VM_CONTINUE(); /* Never reached */ } - EX(call) = zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION, - fbc, opline->extended_value, called_scope, object, EX(call)); - CHECK_EXCEPTION(); - ZEND_VM_NEXT_OPCODE(); + } else if ((IS_CV & (IS_VAR|IS_CV)) && Z_TYPE_P(function_name) == IS_REFERENCE) { + function_name = Z_REFVAL_P(function_name); + goto try_function_name; + } 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(ZEND_CALL_NESTED_FUNCTION, + fbc, opline->extended_value, called_scope, object, EX(call)); + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); } static int ZEND_FASTCALL ZEND_FETCH_CLASS_SPEC_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -2143,155 +2118,129 @@ try_class_name: } } -static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +static int ZEND_FASTCALL ZEND_INIT_DYNAMIC_CALL_SPEC_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE zend_function *fbc; zval *function_name, *func; + zend_string *lcname; + zend_free_op free_op2; + zend_class_entry *called_scope; + zend_object *object; - if ((IS_TMP_VAR|IS_VAR) == IS_CONST) { - if (EXPECTED(CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2))))) { - fbc = CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2))); + SAVE_OPLINE(); + function_name = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2); + +try_function_name: + if ((IS_TMP_VAR|IS_VAR) != IS_CONST && EXPECTED(Z_TYPE_P(function_name) == IS_STRING)) { + if (Z_STRVAL_P(function_name)[0] == '\\') { + lcname = zend_string_alloc(Z_STRLEN_P(function_name) - 1, 0); + zend_str_tolower_copy(lcname->val, Z_STRVAL_P(function_name) + 1, Z_STRLEN_P(function_name) - 1); } else { - if (UNEXPECTED(Z_TYPE_P(EX_CONSTANT(opline->op2)) != IS_STRING)) { - goto init_fcall_complex; - } - function_name = (zval*)(EX_CONSTANT(opline->op2)+1); - if (UNEXPECTED((func = zend_hash_find(EG(function_table), Z_STR_P(function_name))) == NULL)) { - SAVE_OPLINE(); - zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(EX_CONSTANT(opline->op2))); - } else { - fbc = Z_FUNC_P(func); - CACHE_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)), fbc); - } + lcname = zend_string_tolower(Z_STR_P(function_name)); } - EX(call) = zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION, - fbc, opline->extended_value, NULL, NULL, EX(call)); - - /*CHECK_EXCEPTION();*/ - ZEND_VM_NEXT_OPCODE(); - } else { - zend_string *lcname; - zend_free_op free_op2; - zend_class_entry *called_scope; - zend_object *object; - -init_fcall_complex: - SAVE_OPLINE(); - function_name = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2); + if (UNEXPECTED((func = zend_hash_find(EG(function_table), lcname)) == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(function_name)); + } + zend_string_release(lcname); + zval_ptr_dtor_nogc(free_op2); -try_function_name: - if ((IS_TMP_VAR|IS_VAR) != IS_CONST && EXPECTED(Z_TYPE_P(function_name) == IS_STRING)) { - if (Z_STRVAL_P(function_name)[0] == '\\') { - lcname = zend_string_alloc(Z_STRLEN_P(function_name) - 1, 0); - zend_str_tolower_copy(lcname->val, Z_STRVAL_P(function_name) + 1, Z_STRLEN_P(function_name) - 1); - } else { - lcname = zend_string_tolower(Z_STR_P(function_name)); - } - if (UNEXPECTED((func = zend_hash_find(EG(function_table), lcname)) == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(function_name)); - } - zend_string_release(lcname); + fbc = Z_FUNC_P(func); + called_scope = NULL; + object = NULL; + } else if ((IS_TMP_VAR|IS_VAR) != IS_CONST && + 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, &called_scope, &fbc, &object) == SUCCESS) { + if (object) { + GC_REFCOUNT(object)++; + } + if ((IS_TMP_VAR|IS_VAR) == IS_VAR && (fbc->common.fn_flags & ZEND_ACC_CLOSURE)) { + /* Delay closure destruction until its invocation */ + fbc->common.prototype = (zend_function*)Z_OBJ_P(free_op2); + } else if ((IS_TMP_VAR|IS_VAR) == IS_CV) { zval_ptr_dtor_nogc(free_op2); + } + } else if (EXPECTED(Z_TYPE_P(function_name) == IS_ARRAY) && + zend_hash_num_elements(Z_ARRVAL_P(function_name)) == 2) { + zval *obj; + zval *method; + obj = zend_hash_index_find(Z_ARRVAL_P(function_name), 0); + method = zend_hash_index_find(Z_ARRVAL_P(function_name), 1); - fbc = Z_FUNC_P(func); - called_scope = NULL; - object = NULL; - } else if ((IS_TMP_VAR|IS_VAR) != IS_CONST && - 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, &called_scope, &fbc, &object) == SUCCESS) { - if (object) { - GC_REFCOUNT(object)++; - } - if ((IS_TMP_VAR|IS_VAR) == IS_VAR && (fbc->common.fn_flags & ZEND_ACC_CLOSURE)) { - /* Delay closure destruction until its invocation */ - fbc->common.prototype = (zend_function*)Z_OBJ_P(free_op2); - } else if ((IS_TMP_VAR|IS_VAR) == IS_CV) { - zval_ptr_dtor_nogc(free_op2); - } - } else if (EXPECTED(Z_TYPE_P(function_name) == IS_ARRAY) && - zend_hash_num_elements(Z_ARRVAL_P(function_name)) == 2) { - zval *obj; - zval *method; + if (!obj || !method) { + zend_error_noreturn(E_ERROR, "Array callback has to contain indices 0 and 1"); + } - obj = zend_hash_index_find(Z_ARRVAL_P(function_name), 0); - method = zend_hash_index_find(Z_ARRVAL_P(function_name), 1); + ZVAL_DEREF(obj); + if (Z_TYPE_P(obj) != IS_STRING && Z_TYPE_P(obj) != IS_OBJECT) { + zend_error_noreturn(E_ERROR, "First array member is not a valid class name or object"); + } - if (!obj || !method) { - zend_error_noreturn(E_ERROR, "Array callback has to contain indices 0 and 1"); - } + ZVAL_DEREF(method); + if (Z_TYPE_P(method) != IS_STRING) { + zend_error_noreturn(E_ERROR, "Second array member is not a valid method"); + } - ZVAL_DEREF(obj); - if (Z_TYPE_P(obj) != IS_STRING && Z_TYPE_P(obj) != IS_OBJECT) { - zend_error_noreturn(E_ERROR, "First array member is not a valid class name or object"); + if (Z_TYPE_P(obj) == IS_STRING) { + object = NULL; + called_scope = zend_fetch_class_by_name(Z_STR_P(obj), NULL, 0); + if (UNEXPECTED(called_scope == NULL)) { + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); } - ZVAL_DEREF(method); - if (Z_TYPE_P(method) != IS_STRING) { - zend_error_noreturn(E_ERROR, "Second array member is not a valid method"); + if (called_scope->get_static_method) { + fbc = called_scope->get_static_method(called_scope, Z_STR_P(method)); + } else { + fbc = zend_std_get_static_method(called_scope, Z_STR_P(method), NULL); } - - if (Z_TYPE_P(obj) == IS_STRING) { - object = NULL; - called_scope = zend_fetch_class_by_name(Z_STR_P(obj), NULL, 0); - if (UNEXPECTED(called_scope == NULL)) { - CHECK_EXCEPTION(); - ZEND_VM_NEXT_OPCODE(); - } - - if (called_scope->get_static_method) { - fbc = called_scope->get_static_method(called_scope, Z_STR_P(method)); - } else { - fbc = zend_std_get_static_method(called_scope, Z_STR_P(method), NULL); - } - 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, + 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); - 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 */ + zend_error_noreturn( + E_ERROR, + "Non-static method %s::%s() cannot be called statically", + fbc->common.scope->name->val, fbc->common.function_name->val); } } - zval_ptr_dtor_nogc(free_op2); - } else if (((IS_TMP_VAR|IS_VAR) & (IS_VAR|IS_CV)) && Z_TYPE_P(function_name) == IS_REFERENCE) { - function_name = Z_REFVAL_P(function_name); - goto try_function_name; } else { - if (UNEXPECTED(EG(exception) != NULL)) { - HANDLE_EXCEPTION(); + 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); + if (UNEXPECTED(fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", object->ce->name->val, Z_STRVAL_P(method)); } - zend_error_noreturn(E_ERROR, "Function name must be a string"); - ZEND_VM_CONTINUE(); /* Never reached */ - } - EX(call) = zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION, - fbc, opline->extended_value, called_scope, object, EX(call)); - CHECK_EXCEPTION(); - ZEND_VM_NEXT_OPCODE(); + if ((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + object = NULL; + } else { + GC_REFCOUNT(object)++; /* For $this pointer */ + } + } + zval_ptr_dtor_nogc(free_op2); + } else if (((IS_TMP_VAR|IS_VAR) & (IS_VAR|IS_CV)) && Z_TYPE_P(function_name) == IS_REFERENCE) { + function_name = Z_REFVAL_P(function_name); + goto try_function_name; + } 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(ZEND_CALL_NESTED_FUNCTION, + fbc, opline->extended_value, called_scope, object, EX(call)); + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); } static int ZEND_FASTCALL ZEND_BW_NOT_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -19481,6 +19430,7 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_CONST_HANDLER(ZEND_O if (opline->opcode == ZEND_INIT_FCALL || opline->opcode == ZEND_INIT_FCALL_BY_NAME || opline->opcode == ZEND_INIT_NS_FCALL_BY_NAME || + opline->opcode == ZEND_INIT_DYNAMIC_CALL || opline->opcode == ZEND_INIT_METHOD_CALL || opline->opcode == ZEND_INIT_STATIC_METHOD_CALL || opline->opcode == ZEND_INIT_USER_CALL || @@ -21687,6 +21637,7 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_CV_HANDLER(ZEND_OPCO if (opline->opcode == ZEND_INIT_FCALL || opline->opcode == ZEND_INIT_FCALL_BY_NAME || opline->opcode == ZEND_INIT_NS_FCALL_BY_NAME || + opline->opcode == ZEND_INIT_DYNAMIC_CALL || opline->opcode == ZEND_INIT_METHOD_CALL || opline->opcode == ZEND_INIT_STATIC_METHOD_CALL || opline->opcode == ZEND_INIT_USER_CALL || @@ -23077,6 +23028,7 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_TMPVAR_HANDLER(ZEND_ if (opline->opcode == ZEND_INIT_FCALL || opline->opcode == ZEND_INIT_FCALL_BY_NAME || opline->opcode == ZEND_INIT_NS_FCALL_BY_NAME || + opline->opcode == ZEND_INIT_DYNAMIC_CALL || opline->opcode == ZEND_INIT_METHOD_CALL || opline->opcode == ZEND_INIT_STATIC_METHOD_CALL || opline->opcode == ZEND_INIT_USER_CALL || @@ -26568,6 +26520,7 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_CONST_HANDLER(ZEND_OPCOD if (opline->opcode == ZEND_INIT_FCALL || opline->opcode == ZEND_INIT_FCALL_BY_NAME || opline->opcode == ZEND_INIT_NS_FCALL_BY_NAME || + opline->opcode == ZEND_INIT_DYNAMIC_CALL || opline->opcode == ZEND_INIT_METHOD_CALL || opline->opcode == ZEND_INIT_STATIC_METHOD_CALL || opline->opcode == ZEND_INIT_USER_CALL || @@ -30796,6 +30749,7 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_CV_HANDLER(ZEND_OPCODE_H if (opline->opcode == ZEND_INIT_FCALL || opline->opcode == ZEND_INIT_FCALL_BY_NAME || opline->opcode == ZEND_INIT_NS_FCALL_BY_NAME || + opline->opcode == ZEND_INIT_DYNAMIC_CALL || opline->opcode == ZEND_INIT_METHOD_CALL || opline->opcode == ZEND_INIT_STATIC_METHOD_CALL || opline->opcode == ZEND_INIT_USER_CALL || @@ -32765,6 +32719,7 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_TMPVAR_HANDLER(ZEND_OPCO if (opline->opcode == ZEND_INIT_FCALL || opline->opcode == ZEND_INIT_FCALL_BY_NAME || opline->opcode == ZEND_INIT_NS_FCALL_BY_NAME || + opline->opcode == ZEND_INIT_DYNAMIC_CALL || opline->opcode == ZEND_INIT_METHOD_CALL || opline->opcode == ZEND_INIT_STATIC_METHOD_CALL || opline->opcode == ZEND_INIT_USER_CALL || @@ -34437,6 +34392,7 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMPVAR_CONST_HANDLER(ZEND_O if (opline->opcode == ZEND_INIT_FCALL || opline->opcode == ZEND_INIT_FCALL_BY_NAME || opline->opcode == ZEND_INIT_NS_FCALL_BY_NAME || + opline->opcode == ZEND_INIT_DYNAMIC_CALL || opline->opcode == ZEND_INIT_METHOD_CALL || opline->opcode == ZEND_INIT_STATIC_METHOD_CALL || opline->opcode == ZEND_INIT_USER_CALL || @@ -36051,6 +36007,7 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMPVAR_CV_HANDLER(ZEND_OPCO if (opline->opcode == ZEND_INIT_FCALL || opline->opcode == ZEND_INIT_FCALL_BY_NAME || opline->opcode == ZEND_INIT_NS_FCALL_BY_NAME || + opline->opcode == ZEND_INIT_DYNAMIC_CALL || opline->opcode == ZEND_INIT_METHOD_CALL || opline->opcode == ZEND_INIT_STATIC_METHOD_CALL || opline->opcode == ZEND_INIT_USER_CALL || @@ -36710,6 +36667,7 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMPVAR_TMPVAR_HANDLER(ZEND_ if (opline->opcode == ZEND_INIT_FCALL || opline->opcode == ZEND_INIT_FCALL_BY_NAME || opline->opcode == ZEND_INIT_NS_FCALL_BY_NAME || + opline->opcode == ZEND_INIT_DYNAMIC_CALL || opline->opcode == ZEND_INIT_METHOD_CALL || opline->opcode == ZEND_INIT_STATIC_METHOD_CALL || opline->opcode == ZEND_INIT_USER_CALL || @@ -38448,30 +38406,30 @@ void zend_init_opcodes_handlers(void) ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_INIT_FCALL_BY_NAME_SPEC_CONST_HANDLER, - ZEND_INIT_FCALL_BY_NAME_SPEC_TMPVAR_HANDLER, - ZEND_INIT_FCALL_BY_NAME_SPEC_TMPVAR_HANDLER, ZEND_NULL_HANDLER, - ZEND_INIT_FCALL_BY_NAME_SPEC_CV_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, ZEND_INIT_FCALL_BY_NAME_SPEC_CONST_HANDLER, - ZEND_INIT_FCALL_BY_NAME_SPEC_TMPVAR_HANDLER, - ZEND_INIT_FCALL_BY_NAME_SPEC_TMPVAR_HANDLER, ZEND_NULL_HANDLER, - ZEND_INIT_FCALL_BY_NAME_SPEC_CV_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, ZEND_INIT_FCALL_BY_NAME_SPEC_CONST_HANDLER, - ZEND_INIT_FCALL_BY_NAME_SPEC_TMPVAR_HANDLER, - ZEND_INIT_FCALL_BY_NAME_SPEC_TMPVAR_HANDLER, ZEND_NULL_HANDLER, - ZEND_INIT_FCALL_BY_NAME_SPEC_CV_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, ZEND_INIT_FCALL_BY_NAME_SPEC_CONST_HANDLER, - ZEND_INIT_FCALL_BY_NAME_SPEC_TMPVAR_HANDLER, - ZEND_INIT_FCALL_BY_NAME_SPEC_TMPVAR_HANDLER, ZEND_NULL_HANDLER, - ZEND_INIT_FCALL_BY_NAME_SPEC_CV_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, ZEND_INIT_FCALL_BY_NAME_SPEC_CONST_HANDLER, - ZEND_INIT_FCALL_BY_NAME_SPEC_TMPVAR_HANDLER, - ZEND_INIT_FCALL_BY_NAME_SPEC_TMPVAR_HANDLER, ZEND_NULL_HANDLER, - ZEND_INIT_FCALL_BY_NAME_SPEC_CV_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, ZEND_DO_FCALL_SPEC_HANDLER, ZEND_DO_FCALL_SPEC_HANDLER, ZEND_DO_FCALL_SPEC_HANDLER, @@ -40172,31 +40130,31 @@ void zend_init_opcodes_handlers(void) ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, + ZEND_INIT_DYNAMIC_CALL_SPEC_CONST_HANDLER, + ZEND_INIT_DYNAMIC_CALL_SPEC_TMPVAR_HANDLER, + ZEND_INIT_DYNAMIC_CALL_SPEC_TMPVAR_HANDLER, ZEND_NULL_HANDLER, + ZEND_INIT_DYNAMIC_CALL_SPEC_CV_HANDLER, + ZEND_INIT_DYNAMIC_CALL_SPEC_CONST_HANDLER, + ZEND_INIT_DYNAMIC_CALL_SPEC_TMPVAR_HANDLER, + ZEND_INIT_DYNAMIC_CALL_SPEC_TMPVAR_HANDLER, ZEND_NULL_HANDLER, + ZEND_INIT_DYNAMIC_CALL_SPEC_CV_HANDLER, + ZEND_INIT_DYNAMIC_CALL_SPEC_CONST_HANDLER, + ZEND_INIT_DYNAMIC_CALL_SPEC_TMPVAR_HANDLER, + ZEND_INIT_DYNAMIC_CALL_SPEC_TMPVAR_HANDLER, ZEND_NULL_HANDLER, + ZEND_INIT_DYNAMIC_CALL_SPEC_CV_HANDLER, + ZEND_INIT_DYNAMIC_CALL_SPEC_CONST_HANDLER, + ZEND_INIT_DYNAMIC_CALL_SPEC_TMPVAR_HANDLER, + ZEND_INIT_DYNAMIC_CALL_SPEC_TMPVAR_HANDLER, ZEND_NULL_HANDLER, + ZEND_INIT_DYNAMIC_CALL_SPEC_CV_HANDLER, + ZEND_INIT_DYNAMIC_CALL_SPEC_CONST_HANDLER, + ZEND_INIT_DYNAMIC_CALL_SPEC_TMPVAR_HANDLER, + ZEND_INIT_DYNAMIC_CALL_SPEC_TMPVAR_HANDLER, ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, + ZEND_INIT_DYNAMIC_CALL_SPEC_CV_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, diff --git a/Zend/zend_vm_opcodes.c b/Zend/zend_vm_opcodes.c index 33f67e6f4b..1ab2a9e0fa 100644 --- a/Zend/zend_vm_opcodes.c +++ b/Zend/zend_vm_opcodes.c @@ -150,7 +150,7 @@ const char *zend_vm_opcodes_map[171] = { "ZEND_FE_RESET_RW", "ZEND_FE_FETCH_RW", "ZEND_FE_FREE", - NULL, + "ZEND_INIT_DYNAMIC_CALL", NULL, NULL, NULL, diff --git a/Zend/zend_vm_opcodes.h b/Zend/zend_vm_opcodes.h index 4764e39094..d21ff08e7f 100644 --- a/Zend/zend_vm_opcodes.h +++ b/Zend/zend_vm_opcodes.h @@ -152,6 +152,7 @@ END_EXTERN_C() #define ZEND_FE_RESET_RW 125 #define ZEND_FE_FETCH_RW 126 #define ZEND_FE_FREE 127 +#define ZEND_INIT_DYNAMIC_CALL 128 #define ZEND_PRE_INC_OBJ 132 #define ZEND_PRE_DEC_OBJ 133 #define ZEND_POST_INC_OBJ 134 diff --git a/ext/opcache/Optimizer/compact_literals.c b/ext/opcache/Optimizer/compact_literals.c index 3e44769cc9..1ac7265e1c 100644 --- a/ext/opcache/Optimizer/compact_literals.c +++ b/ext/opcache/Optimizer/compact_literals.c @@ -139,9 +139,7 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx LITERAL_INFO(opline->op2.constant, LITERAL_FUNC, 1, 1, 1); break; case ZEND_INIT_FCALL_BY_NAME: - if (ZEND_OP2_TYPE(opline) == IS_CONST) { - LITERAL_INFO(opline->op2.constant, LITERAL_FUNC, 1, 1, 2); - } + LITERAL_INFO(opline->op2.constant, LITERAL_FUNC, 1, 1, 2); break; case ZEND_INIT_NS_FCALL_BY_NAME: LITERAL_INFO(opline->op2.constant, LITERAL_FUNC, 1, 1, 3); diff --git a/ext/opcache/Optimizer/optimize_func_calls.c b/ext/opcache/Optimizer/optimize_func_calls.c index 78c6def625..a83adab5ec 100644 --- a/ext/opcache/Optimizer/optimize_func_calls.c +++ b/ext/opcache/Optimizer/optimize_func_calls.c @@ -66,6 +66,7 @@ void optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx) } /* break missing intentionally */ case ZEND_NEW: + case ZEND_INIT_DYNAMIC_CALL: case ZEND_INIT_METHOD_CALL: case ZEND_INIT_STATIC_METHOD_CALL: case ZEND_INIT_FCALL: diff --git a/ext/opcache/Optimizer/zend_optimizer.c b/ext/opcache/Optimizer/zend_optimizer.c index 191e13ca1d..eab51c7f66 100644 --- a/ext/opcache/Optimizer/zend_optimizer.c +++ b/ext/opcache/Optimizer/zend_optimizer.c @@ -180,6 +180,13 @@ void zend_optimizer_update_op2_const(zend_op_array *op_array, zend_optimizer_add_literal(op_array, val); zend_string_hash_val(Z_STR(op_array->literals[opline->op2.constant+1])); break; + case ZEND_INIT_DYNAMIC_CALL: + opline->opcode = ZEND_INIT_FCALL_BY_NAME; + Z_CACHE_SLOT(op_array->literals[opline->op2.constant]) = op_array->last_cache_slot++; + zend_str_tolower(Z_STRVAL_P(val), Z_STRLEN_P(val)); + zend_optimizer_add_literal(op_array, val); + zend_string_hash_val(Z_STR(op_array->literals[opline->op2.constant+1])); + break; case ZEND_INIT_METHOD_CALL: case ZEND_INIT_STATIC_METHOD_CALL: zend_str_tolower(Z_STRVAL_P(val), Z_STRLEN_P(val)); |
