From: Dmitry Stogov Date: Thu, 22 Nov 2007 09:03:11 +0000 (+0000) Subject: Speed-up of ZEND_DO_FCALL and ZEND_INIT_FCALL_BY_NAME by lowercasing and calculating... X-Git-Tag: RELEASE_2_0_0a1~1309 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=32ff00efce3f3b656bbf7ac6f4755756973942e6;p=php Speed-up of ZEND_DO_FCALL and ZEND_INIT_FCALL_BY_NAME by lowercasing and calculating hash values at compile time. --- diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 9facc210bb..f49bbcf1c6 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -1528,6 +1528,7 @@ void zend_do_begin_method_call(znode *left_bracket TSRMLS_DC) /* {{{ */ { zend_op *last_op; int last_op_number; + unsigned int len; unsigned char *ptr = NULL; zend_do_end_variable_parse(BP_VAR_R, 0 TSRMLS_CC); @@ -1558,8 +1559,16 @@ void zend_do_begin_method_call(znode *left_bracket TSRMLS_DC) /* {{{ */ zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_INIT_FCALL_BY_NAME; opline->op2 = *left_bracket; - opline->extended_value = 0; - SET_UNUSED(opline->op1); + if (opline->op2.op_type == IS_CONST) { + opline->op1.op_type = IS_CONST; + Z_TYPE(opline->op1.u.constant) = Z_TYPE(opline->op2.u.constant); + Z_UNIVAL(opline->op1.u.constant) = zend_u_str_case_fold(Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant), Z_UNILEN(opline->op2.u.constant), 0, &len); + Z_UNILEN(opline->op1.u.constant) = len; + opline->extended_value = zend_u_hash_func(Z_TYPE(opline->op1.u.constant), Z_UNIVAL(opline->op1.u.constant), Z_UNILEN(opline->op1.u.constant) + 1); + } else { + opline->extended_value = 0; + SET_UNUSED(opline->op1); + } } zend_stack_push(&CG(function_call_stack), (void *) &ptr, sizeof(zend_function *)); @@ -1583,20 +1592,48 @@ void zend_do_clone(znode *result, znode *expr TSRMLS_DC) /* {{{ */ void zend_do_begin_dynamic_function_call(znode *function_name, int prefix_len TSRMLS_DC) /* {{{ */ { unsigned char *ptr = NULL; + unsigned int len; zend_op *opline; opline = get_next_op(CG(active_op_array) TSRMLS_CC); - opline->opcode = ZEND_INIT_FCALL_BY_NAME; - opline->op2 = *function_name; - opline->extended_value = 0; if (prefix_len) { /* In run-time PHP will check for function with full name and internal function with short name */ + opline->opcode = ZEND_INIT_NS_FCALL_BY_NAME; + opline->op2 = *function_name; + opline->extended_value = 0; opline->op1.op_type = IS_CONST; - ZVAL_LONG(&opline->op1.u.constant, prefix_len); + Z_TYPE(opline->op1.u.constant) = Z_TYPE(opline->op2.u.constant); + Z_UNIVAL(opline->op1.u.constant) = zend_u_str_case_fold(Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant), Z_UNILEN(opline->op2.u.constant), 0, &len); + Z_UNILEN(opline->op1.u.constant) = len; + opline->extended_value = zend_u_hash_func(Z_TYPE(opline->op1.u.constant), Z_UNIVAL(opline->op1.u.constant), Z_UNILEN(opline->op1.u.constant) + 1); + opline = get_next_op(CG(active_op_array) TSRMLS_CC); + opline->opcode = ZEND_OP_DATA; + opline->op1.op_type = IS_CONST; + if (Z_TYPE(function_name->u.constant) == IS_UNICODE) { + Z_TYPE(opline->op1.u.constant) = IS_UNICODE; + Z_UNIVAL(opline->op1.u.constant) = zend_u_str_case_fold(IS_UNICODE, ZSTR(Z_USTRVAL(function_name->u.constant) + prefix_len), Z_USTRLEN(function_name->u.constant) - prefix_len, 0, &len); + Z_UNILEN(opline->op1.u.constant) = len; + } else { + Z_TYPE(opline->op1.u.constant) = IS_STRING; + Z_STRLEN(opline->op1.u.constant) = Z_STRLEN(function_name->u.constant) - prefix_len; + Z_STRVAL(opline->op1.u.constant) = zend_str_tolower_dup(Z_STRVAL(function_name->u.constant) + prefix_len, Z_STRLEN(opline->op1.u.constant)); + } + opline->extended_value = zend_u_hash_func(Z_TYPE(opline->op1.u.constant), Z_UNIVAL(opline->op1.u.constant), Z_UNILEN(opline->op1.u.constant) + 1); } else { - SET_UNUSED(opline->op1); + opline->opcode = ZEND_INIT_FCALL_BY_NAME; + opline->op2 = *function_name; + if (opline->op2.op_type == IS_CONST) { + opline->op1.op_type = IS_CONST; + Z_TYPE(opline->op1.u.constant) = Z_TYPE(opline->op2.u.constant); + Z_UNIVAL(opline->op1.u.constant) = zend_u_str_case_fold(Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant), Z_UNILEN(opline->op2.u.constant), 0, &len); + Z_UNILEN(opline->op1.u.constant) = len; + opline->extended_value = zend_u_hash_func(Z_TYPE(opline->op1.u.constant), Z_UNIVAL(opline->op1.u.constant), Z_UNILEN(opline->op1.u.constant) + 1); + } else { + opline->extended_value = 0; + SET_UNUSED(opline->op1); + } } zend_stack_push(&CG(function_call_stack), (void *) &ptr, sizeof(zend_function *)); @@ -1902,6 +1939,7 @@ void zend_do_end_function_call(znode *function_name, znode *result, znode *argum if (!is_method && !is_dynamic_fcall && function_name->op_type==IS_CONST) { opline->opcode = ZEND_DO_FCALL; opline->op1 = *function_name; + ZVAL_LONG(&opline->op2.u.constant, zend_u_hash_func(Z_TYPE(function_name->u.constant), Z_UNIVAL(function_name->u.constant), Z_UNILEN(function_name->u.constant) + 1)); } else { opline->opcode = ZEND_DO_FCALL_BY_NAME; SET_UNUSED(opline->op1); @@ -3900,6 +3938,7 @@ void zend_do_fetch_constant(znode *result, znode *constant_container, znode *con The additional names are stored in additional OP_DATA opcode. */ zstr nsname; unsigned int nsname_len; + unsigned int len; opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_OP_DATA; @@ -3920,7 +3959,8 @@ void zend_do_fetch_constant(znode *result, znode *constant_container, znode *con } Z_TYPE(opline->op1.u.constant) = Z_TYPE(constant_container->u.constant); - Z_UNIVAL(opline->op1.u.constant) = zend_u_str_case_fold(Z_TYPE(constant_container->u.constant), nsname, nsname_len, 0, &Z_UNILEN(opline->op1.u.constant)); + Z_UNIVAL(opline->op1.u.constant) = zend_u_str_case_fold(Z_TYPE(constant_container->u.constant), nsname, nsname_len, 0, &len); + Z_UNILEN(opline->op1.u.constant) = len; if (UG(unicode)) { Z_USTRVAL(opline->op1.u.constant) = erealloc(Z_USTRVAL(opline->op1.u.constant), UBYTES(Z_USTRLEN(opline->op1.u.constant) + 2 + Z_USTRLEN(constant_name->u.constant) + 1)); Z_USTRVAL(opline->op1.u.constant)[Z_USTRLEN(opline->op1.u.constant)] = ':'; @@ -3970,6 +4010,7 @@ void zend_do_shell_exec(znode *result, znode *cmd TSRMLS_DC) /* {{{ */ opline->op1.op_type = IS_CONST; opline->extended_value = 1; SET_UNUSED(opline->op2); + ZVAL_LONG(&opline->op2.u.constant, zend_u_hash_func(Z_TYPE(opline->op1.u.constant), Z_UNIVAL(opline->op1.u.constant), Z_UNILEN(opline->op1.u.constant)+1)); *result = opline->result; } /* }}} */ diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 7227a8fc46..cfc603266a 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -1930,83 +1930,72 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMP|VAR|CV) { zend_op *opline = EX(opline); zval *function_name; - zend_function *function; zstr function_name_strval, lcname; unsigned int function_name_strlen, lcname_len; zend_free_op free_op2; + int ret; zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); if (OP2_TYPE == IS_CONST) { function_name = &opline->op2.u.constant; + function_name_strval = Z_UNIVAL_P(function_name); + ret = zend_u_hash_quick_find(EG(function_table), Z_TYPE(opline->op1.u.constant), Z_UNIVAL(opline->op1.u.constant), Z_STRLEN(opline->op1.u.constant)+1, opline->extended_value, (void **) &EX(fbc)); } else { function_name = GET_OP2_ZVAL_PTR(BP_VAR_R); if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { zend_error_noreturn(E_ERROR, "Function name must be a string"); } - } - function_name_strval = Z_UNIVAL_P(function_name); - function_name_strlen = Z_UNILEN_P(function_name); - - if (OP2_TYPE != IS_CONST && - ((Z_TYPE_P(function_name) == IS_UNICODE && - Z_USTRVAL_P(function_name)[0] == ':' && - Z_USTRVAL_P(function_name)[1] == ':') || - (Z_TYPE_P(function_name) == IS_STRING && - Z_STRVAL_P(function_name)[0] == ':' && - Z_STRVAL_P(function_name)[1] == ':'))) { - if (Z_TYPE_P(function_name) == IS_UNICODE) { - zstr tmp; - - tmp.u = Z_USTRVAL_P(function_name) + 2; - lcname = zend_u_str_case_fold(IS_UNICODE, tmp, function_name_strlen-2, 1, &lcname_len); + function_name_strval = Z_UNIVAL_P(function_name); + function_name_strlen = Z_UNILEN_P(function_name); + if (Z_TYPE_P(function_name) == IS_UNICODE && + function_name_strval.u[0] == ':' && + function_name_strval.u[1] == ':') { + function_name_strlen -= 2; + lcname = zend_u_str_case_fold(Z_TYPE_P(function_name), ZSTR(function_name_strval.u+2), function_name_strlen, 1, &lcname_len); + } else if (Z_TYPE_P(function_name) == IS_STRING && + function_name_strval.s[0] == ':' && + function_name_strval.s[1] == ':') { + function_name_strlen -= 2; + lcname = zend_u_str_case_fold(Z_TYPE_P(function_name), ZSTR(function_name_strval.s+2), function_name_strlen, 1, &lcname_len); } else { - zstr tmp; - - tmp.s = Z_STRVAL_P(function_name) + 2; - lcname = zend_u_str_case_fold(IS_STRING, tmp, function_name_strlen-2, 1, &lcname_len); + lcname = zend_u_str_case_fold(Z_TYPE_P(function_name), function_name_strval, function_name_strlen, 1, &lcname_len); } - } else { - lcname = zend_u_str_case_fold(Z_TYPE_P(function_name), Z_UNIVAL_P(function_name), function_name_strlen, 1, &lcname_len); - } - if (zend_u_hash_find(EG(function_table), Z_TYPE_P(function_name), lcname, lcname_len+1, (void **) &function)==FAILURE) { + ret = zend_u_hash_find(EG(function_table), Z_TYPE_P(function_name), lcname, lcname_len+1, (void **) &EX(fbc)); efree(lcname.v); - - if (OP2_TYPE == IS_CONST && opline->op1.op_type == IS_CONST) { - if (Z_TYPE_P(function_name) == IS_UNICODE) { - zstr tmp; - - tmp.u = Z_USTRVAL_P(function_name) + Z_LVAL(opline->op1.u.constant); - lcname = zend_u_str_case_fold(IS_UNICODE, tmp, function_name_strlen-Z_LVAL(opline->op1.u.constant), 1, &lcname_len); - } else { - zstr tmp; - - tmp.s = Z_STRVAL_P(function_name) + Z_LVAL(opline->op1.u.constant); - lcname = zend_u_str_case_fold(IS_STRING, tmp, function_name_strlen-Z_LVAL(opline->op1.u.constant), 1, &lcname_len); - } - if (zend_u_hash_find(EG(function_table), Z_TYPE_P(function_name), lcname, lcname_len+1, (void **) &function)==FAILURE || - function->type != ZEND_INTERNAL_FUNCTION) { - efree(lcname.v); - zend_error_noreturn(E_ERROR, "Call to undefined function %R()", Z_TYPE_P(function_name), function_name_strval); - } - } else { - zend_error_noreturn(E_ERROR, "Call to undefined function %R()", Z_TYPE_P(function_name), function_name_strval); - } + } + if (ret==FAILURE) { + zend_error_noreturn(E_ERROR, "Call to undefined function %R()", Z_TYPE_P(function_name), Z_UNIVAL_P(function_name)); } - efree(lcname.v); if (OP2_TYPE != IS_CONST) { FREE_OP2(); } EX(object) = NULL; - EX(fbc) = function; - ZEND_VM_NEXT_OPCODE(); } +ZEND_VM_HANDLER(69, ZEND_INIT_NS_FCALL_BY_NAME, ANY, CONST) +{ + zend_op *opline = EX(opline); + zend_op *op_data = opline + 1; + + ZEND_VM_INC_OPCODE(); + zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); + + if (zend_u_hash_quick_find(EG(function_table), Z_TYPE(opline->op1.u.constant), Z_UNIVAL(opline->op1.u.constant), Z_UNILEN(opline->op1.u.constant)+1, opline->extended_value, (void **) &EX(fbc))==FAILURE) { + if (zend_u_hash_quick_find(EG(function_table), Z_TYPE(op_data->op1.u.constant), Z_UNIVAL(op_data->op1.u.constant), Z_UNILEN(op_data->op1.u.constant)+1, op_data->extended_value, (void **) &EX(fbc))==FAILURE || + EX(fbc)->type != ZEND_INTERNAL_FUNCTION) { + zend_error_noreturn(E_ERROR, "Call to undefined function %R()", Z_TYPE(opline->op2.u.constant), Z_USTRVAL(opline->op2.u.constant)); + } + } + + EX(object) = NULL; + ZEND_VM_NEXT_OPCODE(); + } ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY) { @@ -2209,7 +2198,7 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, CONST, ANY) zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); - if (zend_u_hash_find(EG(function_table), Z_TYPE_P(fname), Z_UNIVAL_P(fname), Z_UNILEN_P(fname)+1, (void **) &EX(function_state).function)==FAILURE) { + if (zend_u_hash_quick_find(EG(function_table), Z_TYPE_P(fname), Z_UNIVAL_P(fname), Z_UNILEN_P(fname)+1, Z_LVAL(opline->op2.u.constant), (void **) &EX(function_state).function)==FAILURE) { /* FIXME: output identifiers properly */ zend_error_noreturn(E_ERROR, "Call to undefined function %R()", Z_TYPE_P(fname), Z_UNIVAL_P(fname)); } @@ -2583,7 +2572,7 @@ ZEND_VM_HANDLER(51, ZEND_CONT, ANY, CONST) ZEND_VM_JMP(EX(op_array)->opcodes + el->cont); } -ZEND_VM_HANDLER(69, ZEND_GOTO, ANY, CONST) +ZEND_VM_HANDLER(100, ZEND_GOTO, ANY, CONST) { zend_op *brk_opline; zend_op *opline = EX(opline); diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 02952a257c..3ba21f1a94 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -657,83 +657,72 @@ static int ZEND_INIT_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { zend_op *opline = EX(opline); zval *function_name; - zend_function *function; zstr function_name_strval, lcname; unsigned int function_name_strlen, lcname_len; + int ret; zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); if (IS_CONST == IS_CONST) { function_name = &opline->op2.u.constant; + function_name_strval = Z_UNIVAL_P(function_name); + ret = zend_u_hash_quick_find(EG(function_table), Z_TYPE(opline->op1.u.constant), Z_UNIVAL(opline->op1.u.constant), Z_STRLEN(opline->op1.u.constant)+1, opline->extended_value, (void **) &EX(fbc)); } else { function_name = &opline->op2.u.constant; if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { zend_error_noreturn(E_ERROR, "Function name must be a string"); } - } - function_name_strval = Z_UNIVAL_P(function_name); - function_name_strlen = Z_UNILEN_P(function_name); - - if (IS_CONST != IS_CONST && - ((Z_TYPE_P(function_name) == IS_UNICODE && - Z_USTRVAL_P(function_name)[0] == ':' && - Z_USTRVAL_P(function_name)[1] == ':') || - (Z_TYPE_P(function_name) == IS_STRING && - Z_STRVAL_P(function_name)[0] == ':' && - Z_STRVAL_P(function_name)[1] == ':'))) { - if (Z_TYPE_P(function_name) == IS_UNICODE) { - zstr tmp; - - tmp.u = Z_USTRVAL_P(function_name) + 2; - lcname = zend_u_str_case_fold(IS_UNICODE, tmp, function_name_strlen-2, 1, &lcname_len); + function_name_strval = Z_UNIVAL_P(function_name); + function_name_strlen = Z_UNILEN_P(function_name); + if (Z_TYPE_P(function_name) == IS_UNICODE && + function_name_strval.u[0] == ':' && + function_name_strval.u[1] == ':') { + function_name_strlen -= 2; + lcname = zend_u_str_case_fold(Z_TYPE_P(function_name), ZSTR(function_name_strval.u+2), function_name_strlen, 1, &lcname_len); + } else if (Z_TYPE_P(function_name) == IS_STRING && + function_name_strval.s[0] == ':' && + function_name_strval.s[1] == ':') { + function_name_strlen -= 2; + lcname = zend_u_str_case_fold(Z_TYPE_P(function_name), ZSTR(function_name_strval.s+2), function_name_strlen, 1, &lcname_len); } else { - zstr tmp; - - tmp.s = Z_STRVAL_P(function_name) + 2; - lcname = zend_u_str_case_fold(IS_STRING, tmp, function_name_strlen-2, 1, &lcname_len); + lcname = zend_u_str_case_fold(Z_TYPE_P(function_name), function_name_strval, function_name_strlen, 1, &lcname_len); } - } else { - lcname = zend_u_str_case_fold(Z_TYPE_P(function_name), Z_UNIVAL_P(function_name), function_name_strlen, 1, &lcname_len); - } - if (zend_u_hash_find(EG(function_table), Z_TYPE_P(function_name), lcname, lcname_len+1, (void **) &function)==FAILURE) { + ret = zend_u_hash_find(EG(function_table), Z_TYPE_P(function_name), lcname, lcname_len+1, (void **) &EX(fbc)); efree(lcname.v); - - if (IS_CONST == IS_CONST && opline->op1.op_type == IS_CONST) { - if (Z_TYPE_P(function_name) == IS_UNICODE) { - zstr tmp; - - tmp.u = Z_USTRVAL_P(function_name) + Z_LVAL(opline->op1.u.constant); - lcname = zend_u_str_case_fold(IS_UNICODE, tmp, function_name_strlen-Z_LVAL(opline->op1.u.constant), 1, &lcname_len); - } else { - zstr tmp; - - tmp.s = Z_STRVAL_P(function_name) + Z_LVAL(opline->op1.u.constant); - lcname = zend_u_str_case_fold(IS_STRING, tmp, function_name_strlen-Z_LVAL(opline->op1.u.constant), 1, &lcname_len); - } - if (zend_u_hash_find(EG(function_table), Z_TYPE_P(function_name), lcname, lcname_len+1, (void **) &function)==FAILURE || - function->type != ZEND_INTERNAL_FUNCTION) { - efree(lcname.v); - zend_error_noreturn(E_ERROR, "Call to undefined function %R()", Z_TYPE_P(function_name), function_name_strval); - } - } else { - zend_error_noreturn(E_ERROR, "Call to undefined function %R()", Z_TYPE_P(function_name), function_name_strval); - } + } + if (ret==FAILURE) { + zend_error_noreturn(E_ERROR, "Call to undefined function %R()", Z_TYPE_P(function_name), Z_UNIVAL_P(function_name)); } - efree(lcname.v); if (IS_CONST != IS_CONST) { } EX(object) = NULL; - EX(fbc) = function; - ZEND_VM_NEXT_OPCODE(); } +static int ZEND_INIT_NS_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + zend_op *opline = EX(opline); + zend_op *op_data = opline + 1; + + ZEND_VM_INC_OPCODE(); + zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); + + if (zend_u_hash_quick_find(EG(function_table), Z_TYPE(opline->op1.u.constant), Z_UNIVAL(opline->op1.u.constant), Z_UNILEN(opline->op1.u.constant)+1, opline->extended_value, (void **) &EX(fbc))==FAILURE) { + if (zend_u_hash_quick_find(EG(function_table), Z_TYPE(op_data->op1.u.constant), Z_UNIVAL(op_data->op1.u.constant), Z_UNILEN(op_data->op1.u.constant)+1, op_data->extended_value, (void **) &EX(fbc))==FAILURE || + EX(fbc)->type != ZEND_INTERNAL_FUNCTION) { + zend_error_noreturn(E_ERROR, "Call to undefined function %R()", Z_TYPE(opline->op2.u.constant), Z_USTRVAL(opline->op2.u.constant)); + } + } + + EX(object) = NULL; + ZEND_VM_NEXT_OPCODE(); + } static int ZEND_RECV_INIT_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { @@ -855,84 +844,54 @@ static int ZEND_INIT_FCALL_BY_NAME_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { zend_op *opline = EX(opline); zval *function_name; - zend_function *function; zstr function_name_strval, lcname; unsigned int function_name_strlen, lcname_len; zend_free_op free_op2; + int ret; zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); if (IS_TMP_VAR == IS_CONST) { function_name = &opline->op2.u.constant; + function_name_strval = Z_UNIVAL_P(function_name); + ret = zend_u_hash_quick_find(EG(function_table), Z_TYPE(opline->op1.u.constant), Z_UNIVAL(opline->op1.u.constant), Z_STRLEN(opline->op1.u.constant)+1, opline->extended_value, (void **) &EX(fbc)); } else { function_name = _get_zval_ptr_tmp(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC); if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { zend_error_noreturn(E_ERROR, "Function name must be a string"); } - } - function_name_strval = Z_UNIVAL_P(function_name); - function_name_strlen = Z_UNILEN_P(function_name); - - if (IS_TMP_VAR != IS_CONST && - ((Z_TYPE_P(function_name) == IS_UNICODE && - Z_USTRVAL_P(function_name)[0] == ':' && - Z_USTRVAL_P(function_name)[1] == ':') || - (Z_TYPE_P(function_name) == IS_STRING && - Z_STRVAL_P(function_name)[0] == ':' && - Z_STRVAL_P(function_name)[1] == ':'))) { - if (Z_TYPE_P(function_name) == IS_UNICODE) { - zstr tmp; - - tmp.u = Z_USTRVAL_P(function_name) + 2; - lcname = zend_u_str_case_fold(IS_UNICODE, tmp, function_name_strlen-2, 1, &lcname_len); + function_name_strval = Z_UNIVAL_P(function_name); + function_name_strlen = Z_UNILEN_P(function_name); + if (Z_TYPE_P(function_name) == IS_UNICODE && + function_name_strval.u[0] == ':' && + function_name_strval.u[1] == ':') { + function_name_strlen -= 2; + lcname = zend_u_str_case_fold(Z_TYPE_P(function_name), ZSTR(function_name_strval.u+2), function_name_strlen, 1, &lcname_len); + } else if (Z_TYPE_P(function_name) == IS_STRING && + function_name_strval.s[0] == ':' && + function_name_strval.s[1] == ':') { + function_name_strlen -= 2; + lcname = zend_u_str_case_fold(Z_TYPE_P(function_name), ZSTR(function_name_strval.s+2), function_name_strlen, 1, &lcname_len); } else { - zstr tmp; - - tmp.s = Z_STRVAL_P(function_name) + 2; - lcname = zend_u_str_case_fold(IS_STRING, tmp, function_name_strlen-2, 1, &lcname_len); + lcname = zend_u_str_case_fold(Z_TYPE_P(function_name), function_name_strval, function_name_strlen, 1, &lcname_len); } - } else { - lcname = zend_u_str_case_fold(Z_TYPE_P(function_name), Z_UNIVAL_P(function_name), function_name_strlen, 1, &lcname_len); - } - if (zend_u_hash_find(EG(function_table), Z_TYPE_P(function_name), lcname, lcname_len+1, (void **) &function)==FAILURE) { + ret = zend_u_hash_find(EG(function_table), Z_TYPE_P(function_name), lcname, lcname_len+1, (void **) &EX(fbc)); efree(lcname.v); - - if (IS_TMP_VAR == IS_CONST && opline->op1.op_type == IS_CONST) { - if (Z_TYPE_P(function_name) == IS_UNICODE) { - zstr tmp; - - tmp.u = Z_USTRVAL_P(function_name) + Z_LVAL(opline->op1.u.constant); - lcname = zend_u_str_case_fold(IS_UNICODE, tmp, function_name_strlen-Z_LVAL(opline->op1.u.constant), 1, &lcname_len); - } else { - zstr tmp; - - tmp.s = Z_STRVAL_P(function_name) + Z_LVAL(opline->op1.u.constant); - lcname = zend_u_str_case_fold(IS_STRING, tmp, function_name_strlen-Z_LVAL(opline->op1.u.constant), 1, &lcname_len); - } - if (zend_u_hash_find(EG(function_table), Z_TYPE_P(function_name), lcname, lcname_len+1, (void **) &function)==FAILURE || - function->type != ZEND_INTERNAL_FUNCTION) { - efree(lcname.v); - zend_error_noreturn(E_ERROR, "Call to undefined function %R()", Z_TYPE_P(function_name), function_name_strval); - } - } else { - zend_error_noreturn(E_ERROR, "Call to undefined function %R()", Z_TYPE_P(function_name), function_name_strval); - } + } + if (ret==FAILURE) { + zend_error_noreturn(E_ERROR, "Call to undefined function %R()", Z_TYPE_P(function_name), Z_UNIVAL_P(function_name)); } - efree(lcname.v); if (IS_TMP_VAR != IS_CONST) { zval_dtor(free_op2.var); } EX(object) = NULL; - EX(fbc) = function; - ZEND_VM_NEXT_OPCODE(); } - static int ZEND_FETCH_CLASS_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { zend_op *opline = EX(opline); @@ -968,84 +927,54 @@ static int ZEND_INIT_FCALL_BY_NAME_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { zend_op *opline = EX(opline); zval *function_name; - zend_function *function; zstr function_name_strval, lcname; unsigned int function_name_strlen, lcname_len; zend_free_op free_op2; + int ret; zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); if (IS_VAR == IS_CONST) { function_name = &opline->op2.u.constant; + function_name_strval = Z_UNIVAL_P(function_name); + ret = zend_u_hash_quick_find(EG(function_table), Z_TYPE(opline->op1.u.constant), Z_UNIVAL(opline->op1.u.constant), Z_STRLEN(opline->op1.u.constant)+1, opline->extended_value, (void **) &EX(fbc)); } else { function_name = _get_zval_ptr_var(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC); if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { zend_error_noreturn(E_ERROR, "Function name must be a string"); } - } - function_name_strval = Z_UNIVAL_P(function_name); - function_name_strlen = Z_UNILEN_P(function_name); - - if (IS_VAR != IS_CONST && - ((Z_TYPE_P(function_name) == IS_UNICODE && - Z_USTRVAL_P(function_name)[0] == ':' && - Z_USTRVAL_P(function_name)[1] == ':') || - (Z_TYPE_P(function_name) == IS_STRING && - Z_STRVAL_P(function_name)[0] == ':' && - Z_STRVAL_P(function_name)[1] == ':'))) { - if (Z_TYPE_P(function_name) == IS_UNICODE) { - zstr tmp; - - tmp.u = Z_USTRVAL_P(function_name) + 2; - lcname = zend_u_str_case_fold(IS_UNICODE, tmp, function_name_strlen-2, 1, &lcname_len); + function_name_strval = Z_UNIVAL_P(function_name); + function_name_strlen = Z_UNILEN_P(function_name); + if (Z_TYPE_P(function_name) == IS_UNICODE && + function_name_strval.u[0] == ':' && + function_name_strval.u[1] == ':') { + function_name_strlen -= 2; + lcname = zend_u_str_case_fold(Z_TYPE_P(function_name), ZSTR(function_name_strval.u+2), function_name_strlen, 1, &lcname_len); + } else if (Z_TYPE_P(function_name) == IS_STRING && + function_name_strval.s[0] == ':' && + function_name_strval.s[1] == ':') { + function_name_strlen -= 2; + lcname = zend_u_str_case_fold(Z_TYPE_P(function_name), ZSTR(function_name_strval.s+2), function_name_strlen, 1, &lcname_len); } else { - zstr tmp; - - tmp.s = Z_STRVAL_P(function_name) + 2; - lcname = zend_u_str_case_fold(IS_STRING, tmp, function_name_strlen-2, 1, &lcname_len); + lcname = zend_u_str_case_fold(Z_TYPE_P(function_name), function_name_strval, function_name_strlen, 1, &lcname_len); } - } else { - lcname = zend_u_str_case_fold(Z_TYPE_P(function_name), Z_UNIVAL_P(function_name), function_name_strlen, 1, &lcname_len); - } - if (zend_u_hash_find(EG(function_table), Z_TYPE_P(function_name), lcname, lcname_len+1, (void **) &function)==FAILURE) { + ret = zend_u_hash_find(EG(function_table), Z_TYPE_P(function_name), lcname, lcname_len+1, (void **) &EX(fbc)); efree(lcname.v); - - if (IS_VAR == IS_CONST && opline->op1.op_type == IS_CONST) { - if (Z_TYPE_P(function_name) == IS_UNICODE) { - zstr tmp; - - tmp.u = Z_USTRVAL_P(function_name) + Z_LVAL(opline->op1.u.constant); - lcname = zend_u_str_case_fold(IS_UNICODE, tmp, function_name_strlen-Z_LVAL(opline->op1.u.constant), 1, &lcname_len); - } else { - zstr tmp; - - tmp.s = Z_STRVAL_P(function_name) + Z_LVAL(opline->op1.u.constant); - lcname = zend_u_str_case_fold(IS_STRING, tmp, function_name_strlen-Z_LVAL(opline->op1.u.constant), 1, &lcname_len); - } - if (zend_u_hash_find(EG(function_table), Z_TYPE_P(function_name), lcname, lcname_len+1, (void **) &function)==FAILURE || - function->type != ZEND_INTERNAL_FUNCTION) { - efree(lcname.v); - zend_error_noreturn(E_ERROR, "Call to undefined function %R()", Z_TYPE_P(function_name), function_name_strval); - } - } else { - zend_error_noreturn(E_ERROR, "Call to undefined function %R()", Z_TYPE_P(function_name), function_name_strval); - } + } + if (ret==FAILURE) { + zend_error_noreturn(E_ERROR, "Call to undefined function %R()", Z_TYPE_P(function_name), Z_UNIVAL_P(function_name)); } - efree(lcname.v); if (IS_VAR != IS_CONST) { if (free_op2.var) {zval_ptr_dtor(&free_op2.var);}; } EX(object) = NULL; - EX(fbc) = function; - ZEND_VM_NEXT_OPCODE(); } - static int ZEND_FETCH_CLASS_SPEC_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { zend_op *opline = EX(opline); @@ -1110,84 +1039,54 @@ static int ZEND_INIT_FCALL_BY_NAME_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { zend_op *opline = EX(opline); zval *function_name; - zend_function *function; zstr function_name_strval, lcname; unsigned int function_name_strlen, lcname_len; + int ret; zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); if (IS_CV == IS_CONST) { function_name = &opline->op2.u.constant; + function_name_strval = Z_UNIVAL_P(function_name); + ret = zend_u_hash_quick_find(EG(function_table), Z_TYPE(opline->op1.u.constant), Z_UNIVAL(opline->op1.u.constant), Z_STRLEN(opline->op1.u.constant)+1, opline->extended_value, (void **) &EX(fbc)); } else { function_name = _get_zval_ptr_cv(&opline->op2, EX(Ts), BP_VAR_R TSRMLS_CC); if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { zend_error_noreturn(E_ERROR, "Function name must be a string"); } - } - function_name_strval = Z_UNIVAL_P(function_name); - function_name_strlen = Z_UNILEN_P(function_name); - - if (IS_CV != IS_CONST && - ((Z_TYPE_P(function_name) == IS_UNICODE && - Z_USTRVAL_P(function_name)[0] == ':' && - Z_USTRVAL_P(function_name)[1] == ':') || - (Z_TYPE_P(function_name) == IS_STRING && - Z_STRVAL_P(function_name)[0] == ':' && - Z_STRVAL_P(function_name)[1] == ':'))) { - if (Z_TYPE_P(function_name) == IS_UNICODE) { - zstr tmp; - - tmp.u = Z_USTRVAL_P(function_name) + 2; - lcname = zend_u_str_case_fold(IS_UNICODE, tmp, function_name_strlen-2, 1, &lcname_len); + function_name_strval = Z_UNIVAL_P(function_name); + function_name_strlen = Z_UNILEN_P(function_name); + if (Z_TYPE_P(function_name) == IS_UNICODE && + function_name_strval.u[0] == ':' && + function_name_strval.u[1] == ':') { + function_name_strlen -= 2; + lcname = zend_u_str_case_fold(Z_TYPE_P(function_name), ZSTR(function_name_strval.u+2), function_name_strlen, 1, &lcname_len); + } else if (Z_TYPE_P(function_name) == IS_STRING && + function_name_strval.s[0] == ':' && + function_name_strval.s[1] == ':') { + function_name_strlen -= 2; + lcname = zend_u_str_case_fold(Z_TYPE_P(function_name), ZSTR(function_name_strval.s+2), function_name_strlen, 1, &lcname_len); } else { - zstr tmp; - - tmp.s = Z_STRVAL_P(function_name) + 2; - lcname = zend_u_str_case_fold(IS_STRING, tmp, function_name_strlen-2, 1, &lcname_len); + lcname = zend_u_str_case_fold(Z_TYPE_P(function_name), function_name_strval, function_name_strlen, 1, &lcname_len); } - } else { - lcname = zend_u_str_case_fold(Z_TYPE_P(function_name), Z_UNIVAL_P(function_name), function_name_strlen, 1, &lcname_len); - } - if (zend_u_hash_find(EG(function_table), Z_TYPE_P(function_name), lcname, lcname_len+1, (void **) &function)==FAILURE) { + ret = zend_u_hash_find(EG(function_table), Z_TYPE_P(function_name), lcname, lcname_len+1, (void **) &EX(fbc)); efree(lcname.v); - - if (IS_CV == IS_CONST && opline->op1.op_type == IS_CONST) { - if (Z_TYPE_P(function_name) == IS_UNICODE) { - zstr tmp; - - tmp.u = Z_USTRVAL_P(function_name) + Z_LVAL(opline->op1.u.constant); - lcname = zend_u_str_case_fold(IS_UNICODE, tmp, function_name_strlen-Z_LVAL(opline->op1.u.constant), 1, &lcname_len); - } else { - zstr tmp; - - tmp.s = Z_STRVAL_P(function_name) + Z_LVAL(opline->op1.u.constant); - lcname = zend_u_str_case_fold(IS_STRING, tmp, function_name_strlen-Z_LVAL(opline->op1.u.constant), 1, &lcname_len); - } - if (zend_u_hash_find(EG(function_table), Z_TYPE_P(function_name), lcname, lcname_len+1, (void **) &function)==FAILURE || - function->type != ZEND_INTERNAL_FUNCTION) { - efree(lcname.v); - zend_error_noreturn(E_ERROR, "Call to undefined function %R()", Z_TYPE_P(function_name), function_name_strval); - } - } else { - zend_error_noreturn(E_ERROR, "Call to undefined function %R()", Z_TYPE_P(function_name), function_name_strval); - } + } + if (ret==FAILURE) { + zend_error_noreturn(E_ERROR, "Call to undefined function %R()", Z_TYPE_P(function_name), Z_UNIVAL_P(function_name)); } - efree(lcname.v); if (IS_CV != IS_CONST) { } EX(object) = NULL; - EX(fbc) = function; - ZEND_VM_NEXT_OPCODE(); } - static int ZEND_BW_NOT_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { zend_op *opline = EX(opline); @@ -1492,7 +1391,7 @@ static int ZEND_DO_FCALL_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); - if (zend_u_hash_find(EG(function_table), Z_TYPE_P(fname), Z_UNIVAL_P(fname), Z_UNILEN_P(fname)+1, (void **) &EX(function_state).function)==FAILURE) { + if (zend_u_hash_quick_find(EG(function_table), Z_TYPE_P(fname), Z_UNIVAL_P(fname), Z_UNILEN_P(fname)+1, Z_LVAL(opline->op2.u.constant), (void **) &EX(function_state).function)==FAILURE) { /* FIXME: output identifiers properly */ zend_error_noreturn(E_ERROR, "Call to undefined function %R()", Z_TYPE_P(fname), Z_UNIVAL_P(fname)); } @@ -30933,27 +30832,27 @@ void zend_init_opcodes_handlers(void) ZEND_NEW_SPEC_HANDLER, ZEND_NEW_SPEC_HANDLER, ZEND_NEW_SPEC_HANDLER, - ZEND_GOTO_SPEC_CONST_HANDLER, + ZEND_INIT_NS_FCALL_BY_NAME_SPEC_CONST_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, - ZEND_GOTO_SPEC_CONST_HANDLER, + ZEND_INIT_NS_FCALL_BY_NAME_SPEC_CONST_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, - ZEND_GOTO_SPEC_CONST_HANDLER, + ZEND_INIT_NS_FCALL_BY_NAME_SPEC_CONST_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, - ZEND_GOTO_SPEC_CONST_HANDLER, + ZEND_INIT_NS_FCALL_BY_NAME_SPEC_CONST_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, - ZEND_GOTO_SPEC_CONST_HANDLER, + ZEND_INIT_NS_FCALL_BY_NAME_SPEC_CONST_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, @@ -31708,27 +31607,27 @@ void zend_init_opcodes_handlers(void) ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, + ZEND_GOTO_SPEC_CONST_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, + ZEND_GOTO_SPEC_CONST_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, + ZEND_GOTO_SPEC_CONST_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, + ZEND_GOTO_SPEC_CONST_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_GOTO_SPEC_CONST_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, diff --git a/Zend/zend_vm_opcodes.h b/Zend/zend_vm_opcodes.h index b1d88da213..d48887b5a0 100644 --- a/Zend/zend_vm_opcodes.h +++ b/Zend/zend_vm_opcodes.h @@ -87,7 +87,7 @@ #define ZEND_SEND_VAR 66 #define ZEND_SEND_REF 67 #define ZEND_NEW 68 -#define ZEND_GOTO 69 +#define ZEND_INIT_NS_FCALL_BY_NAME 69 #define ZEND_FREE 70 #define ZEND_INIT_ARRAY 71 #define ZEND_ADD_ARRAY_ELEMENT 72 @@ -118,6 +118,7 @@ #define ZEND_FETCH_OBJ_UNSET 97 #define ZEND_FETCH_DIM_TMP_VAR 98 #define ZEND_FETCH_CONSTANT 99 +#define ZEND_GOTO 100 #define ZEND_EXT_STMT 101 #define ZEND_EXT_FCALL_BEGIN 102 #define ZEND_EXT_FCALL_END 103