diff options
Diffstat (limited to 'Zend/zend_operators.c')
-rw-r--r-- | Zend/zend_operators.c | 151 |
1 files changed, 110 insertions, 41 deletions
diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c index d1f2d553fc..db53c71317 100644 --- a/Zend/zend_operators.c +++ b/Zend/zend_operators.c @@ -30,12 +30,21 @@ #include "zend_exceptions.h" #include "zend_closures.h" +#include <locale.h> +#ifdef HAVE_LANGINFO_H +# include <langinfo.h> +#endif + #ifdef __SSE2__ #include <emmintrin.h> #endif +#if defined(ZEND_WIN32) && !defined(ZTS) && defined(_MSC_VER) +/* This performance improvement of tolower() on Windows gives 10-18% on bench.php */ +#define ZEND_USE_TOLOWER_L 1 +#endif + #ifdef ZEND_USE_TOLOWER_L -#include <locale.h> static _locale_t current_locale = NULL; /* this is true global! may lead to strange effects on ZTS, but so may setlocale() */ #define zend_tolower(c) _tolower_l(c, current_locale) @@ -285,7 +294,7 @@ static zend_always_inline zend_result zendi_try_convert_scalar_to_number(zval *o } /* }}} */ -static zend_never_inline zend_long ZEND_FASTCALL zendi_try_get_long(zval *op, zend_bool *failed) /* {{{ */ +static zend_never_inline zend_long ZEND_FASTCALL zendi_try_get_long(zval *op, bool *failed) /* {{{ */ { *failed = 0; switch (Z_TYPE_P(op)) { @@ -377,7 +386,7 @@ static zend_never_inline zend_long ZEND_FASTCALL zendi_try_get_long(zval *op, ze #define convert_op1_op2_long(op1, op1_lval, op2, op2_lval, result, opcode, sigil) \ do { \ if (UNEXPECTED(Z_TYPE_P(op1) != IS_LONG)) { \ - zend_bool failed; \ + bool failed; \ if (Z_ISREF_P(op1)) { \ op1 = Z_REFVAL_P(op1); \ if (Z_TYPE_P(op1) == IS_LONG) { \ @@ -400,7 +409,7 @@ static zend_never_inline zend_long ZEND_FASTCALL zendi_try_get_long(zval *op, ze } while (0); \ do { \ if (UNEXPECTED(Z_TYPE_P(op2) != IS_LONG)) { \ - zend_bool failed; \ + bool failed; \ if (Z_ISREF_P(op2)) { \ op2 = Z_REFVAL_P(op2); \ if (Z_TYPE_P(op2) == IS_LONG) { \ @@ -424,14 +433,6 @@ static zend_never_inline zend_long ZEND_FASTCALL zendi_try_get_long(zval *op, ze ZEND_API void ZEND_FASTCALL convert_to_long(zval *op) /* {{{ */ { - if (Z_TYPE_P(op) != IS_LONG) { - convert_to_long_base(op, 10); - } -} -/* }}} */ - -ZEND_API void ZEND_FASTCALL convert_to_long_base(zval *op, int base) /* {{{ */ -{ zend_long tmp; try_again: @@ -456,11 +457,7 @@ try_again: case IS_STRING: { zend_string *str = Z_STR_P(op); - if (base == 10) { - ZVAL_LONG(op, zval_get_long(op)); - } else { - ZVAL_LONG(op, ZEND_STRTOL(ZSTR_VAL(str), NULL, base)); - } + ZVAL_LONG(op, zval_get_long(op)); zend_string_release_ex(str, 0); } break; @@ -683,7 +680,7 @@ try_again: } /* }}} */ -ZEND_API zend_bool ZEND_FASTCALL _try_convert_to_string(zval *op) /* {{{ */ +ZEND_API bool ZEND_FASTCALL _try_convert_to_string(zval *op) /* {{{ */ { zend_string *str; @@ -716,6 +713,13 @@ try_again: case IS_OBJECT: if (Z_OBJCE_P(op) == zend_ce_closure) { convert_scalar_to_array(op); + } else if (Z_OBJ_P(op)->properties == NULL + && Z_OBJ_HT_P(op)->get_properties_for == NULL + && Z_OBJ_HT_P(op)->get_properties == zend_std_get_properties) { + /* Optimized version without rebulding properties HashTable */ + HashTable *ht = zend_std_build_object_properties_array(Z_OBJ_P(op)); + OBJ_RELEASE(Z_OBJ_P(op)); + ZVAL_ARR(op, ht); } else { HashTable *obj_ht = zend_get_properties_for(op, ZEND_PROP_PURPOSE_ARRAY_CAST); if (obj_ht) { @@ -882,7 +886,7 @@ try_again: } /* }}} */ -static zend_always_inline zend_string* __zval_get_string_func(zval *op, zend_bool try) /* {{{ */ +static zend_always_inline zend_string* __zval_get_string_func(zval *op, bool try) /* {{{ */ { try_again: switch (Z_TYPE_P(op)) { @@ -1530,7 +1534,7 @@ ZEND_API zend_result ZEND_FASTCALL bitwise_or_function(zval *result, zval *op1, } if (UNEXPECTED(Z_TYPE_P(op1) != IS_LONG)) { - zend_bool failed; + bool failed; ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(ZEND_BW_OR); op1_lval = zendi_try_get_long(op1, &failed); if (UNEXPECTED(failed)) { @@ -1544,7 +1548,7 @@ ZEND_API zend_result ZEND_FASTCALL bitwise_or_function(zval *result, zval *op1, op1_lval = Z_LVAL_P(op1); } if (UNEXPECTED(Z_TYPE_P(op2) != IS_LONG)) { - zend_bool failed; + bool failed; ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(ZEND_BW_OR); op2_lval = zendi_try_get_long(op2, &failed); if (UNEXPECTED(failed)) { @@ -1612,7 +1616,7 @@ ZEND_API zend_result ZEND_FASTCALL bitwise_and_function(zval *result, zval *op1, } if (UNEXPECTED(Z_TYPE_P(op1) != IS_LONG)) { - zend_bool failed; + bool failed; ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(ZEND_BW_AND); op1_lval = zendi_try_get_long(op1, &failed); if (UNEXPECTED(failed)) { @@ -1626,7 +1630,7 @@ ZEND_API zend_result ZEND_FASTCALL bitwise_and_function(zval *result, zval *op1, op1_lval = Z_LVAL_P(op1); } if (UNEXPECTED(Z_TYPE_P(op2) != IS_LONG)) { - zend_bool failed; + bool failed; ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(ZEND_BW_AND); op2_lval = zendi_try_get_long(op2, &failed); if (UNEXPECTED(failed)) { @@ -1694,7 +1698,7 @@ ZEND_API zend_result ZEND_FASTCALL bitwise_xor_function(zval *result, zval *op1, } if (UNEXPECTED(Z_TYPE_P(op1) != IS_LONG)) { - zend_bool failed; + bool failed; ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(ZEND_BW_XOR); op1_lval = zendi_try_get_long(op1, &failed); if (UNEXPECTED(failed)) { @@ -1708,7 +1712,7 @@ ZEND_API zend_result ZEND_FASTCALL bitwise_xor_function(zval *result, zval *op1, op1_lval = Z_LVAL_P(op1); } if (UNEXPECTED(Z_TYPE_P(op2) != IS_LONG)) { - zend_bool failed; + bool failed; ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(ZEND_BW_XOR); op2_lval = zendi_try_get_long(op2, &failed); if (UNEXPECTED(failed)) { @@ -1910,7 +1914,7 @@ ZEND_API zend_result ZEND_FASTCALL concat_function(zval *result, zval *op1, zval } /* }}} */ -ZEND_API int ZEND_FASTCALL string_compare_function_ex(zval *op1, zval *op2, zend_bool case_insensitive) /* {{{ */ +ZEND_API int ZEND_FASTCALL string_compare_function_ex(zval *op1, zval *op2, bool case_insensitive) /* {{{ */ { zend_string *tmp_str1, *tmp_str2; zend_string *str1 = zval_get_tmp_string(op1, &tmp_str1); @@ -2194,7 +2198,7 @@ static int hash_zval_identical_function(zval *z1, zval *z2) /* {{{ */ } /* }}} */ -ZEND_API zend_bool ZEND_FASTCALL zend_is_identical(zval *op1, zval *op2) /* {{{ */ +ZEND_API bool ZEND_FASTCALL zend_is_identical(zval *op1, zval *op2) /* {{{ */ { if (Z_TYPE_P(op1) != Z_TYPE_P(op2)) { return 0; @@ -2265,7 +2269,7 @@ ZEND_API zend_result ZEND_FASTCALL is_smaller_or_equal_function(zval *result, zv } /* }}} */ -ZEND_API zend_bool ZEND_FASTCALL zend_class_implements_interface(const zend_class_entry *class_ce, const zend_class_entry *interface_ce) /* {{{ */ +ZEND_API bool ZEND_FASTCALL zend_class_implements_interface(const zend_class_entry *class_ce, const zend_class_entry *interface_ce) /* {{{ */ { uint32_t i; ZEND_ASSERT(!(class_ce->ce_flags & ZEND_ACC_INTERFACE)); @@ -2283,7 +2287,7 @@ ZEND_API zend_bool ZEND_FASTCALL zend_class_implements_interface(const zend_clas } /* }}} */ -ZEND_API zend_bool ZEND_FASTCALL instanceof_function_slow(const zend_class_entry *instance_ce, const zend_class_entry *ce) /* {{{ */ +ZEND_API bool ZEND_FASTCALL instanceof_function_slow(const zend_class_entry *instance_ce, const zend_class_entry *ce) /* {{{ */ { ZEND_ASSERT(instance_ce != ce && "Should have been checked already"); if (ce->ce_flags & ZEND_ACC_INTERFACE) { @@ -2335,8 +2339,10 @@ static void ZEND_FASTCALL increment_string(zval *str) /* {{{ */ Z_STR_P(str) = zend_string_init(Z_STRVAL_P(str), Z_STRLEN_P(str), 0); Z_TYPE_INFO_P(str) = IS_STRING_EX; } else if (Z_REFCOUNT_P(str) > 1) { - Z_DELREF_P(str); + /* Only release string after allocation succeeded. */ + zend_string *orig_str = Z_STR_P(str); Z_STR_P(str) = zend_string_init(Z_STRVAL_P(str), Z_STRLEN_P(str), 0); + GC_DELREF(orig_str); } else { zend_string_forget_hash_val(Z_STR_P(str)); } @@ -2547,13 +2553,85 @@ ZEND_API bool ZEND_FASTCALL zend_object_is_true(zval *op) /* {{{ */ } /* }}} */ -#ifdef ZEND_USE_TOLOWER_L ZEND_API void zend_update_current_locale(void) /* {{{ */ { +#ifdef ZEND_USE_TOLOWER_L +# if defined(ZEND_WIN32) && defined(_MSC_VER) current_locale = _get_current_locale(); +# else + current_locale = uselocale(0); +# endif +#endif +#if defined(ZEND_WIN32) && defined(_MSC_VER) + if (MB_CUR_MAX > 1) { + unsigned int cp = ___lc_codepage_func(); + CG(variable_width_locale) = 1; + // TODO: EUC-* are also ASCII compatible ??? + CG(ascii_compatible_locale) = + cp == 65001; /* UTF-8 */ + } else { + CG(variable_width_locale) = 0; + CG(ascii_compatible_locale) = 1; + } +#elif defined(MB_CUR_MAX) + /* Check if current locale uses variable width encoding */ + if (MB_CUR_MAX > 1) { +#if HAVE_NL_LANGINFO + const char *charmap = nl_langinfo(CODESET); +#else + char buf[16]; + const char *charmap = NULL; + const char *locale = setlocale(LC_CTYPE, NULL); + + if (locale) { + const char *dot = strchr(locale, '.'); + const char *modifier; + + if (dot) { + dot++; + modifier = strchr(dot, '@'); + if (!modifier) { + charmap = dot; + } else if (modifier - dot < sizeof(buf)) { + memcpy(buf, dot, modifier - dot); + buf[modifier - dot] = '\0'; + charmap = buf; + } + } + } +#endif + CG(variable_width_locale) = 1; + CG(ascii_compatible_locale) = 0; + + if (charmap) { + size_t len = strlen(charmap); + static const char *ascii_compatible_charmaps[] = { + "utf-8", + "utf8", + // TODO: EUC-* are also ASCII compatible ??? + NULL + }; + const char **p; + /* Check if current locale is ASCII compatible */ + for (p = ascii_compatible_charmaps; *p; p++) { + if (zend_binary_strcasecmp(charmap, len, *p, strlen(*p)) == 0) { + CG(ascii_compatible_locale) = 1; + break; + } + } + } + + } else { + CG(variable_width_locale) = 0; + CG(ascii_compatible_locale) = 1; + } +#else + /* We can't determine current charset. Assume the worst case */ + CG(variable_width_locale) = 1; + CG(ascii_compatible_locale) = 0; +#endif } /* }}} */ -#endif static zend_always_inline void zend_str_tolower_impl(char *dest, const char *str, size_t length) /* {{{ */ { unsigned char *p = (unsigned char*)str; @@ -2954,15 +3032,6 @@ ZEND_API int ZEND_FASTCALL zend_compare_objects(zval *o1, zval *o2) /* {{{ */ } /* }}} */ -ZEND_API void ZEND_FASTCALL zend_locale_sprintf_double(zval *op ZEND_FILE_LINE_DC) /* {{{ */ -{ - zend_string *str; - - str = zend_strpprintf(0, "%.*G", (int) EG(precision), (double)Z_DVAL_P(op)); - ZVAL_NEW_STR(op, str); -} -/* }}} */ - ZEND_API zend_string* ZEND_FASTCALL zend_long_to_str(zend_long num) /* {{{ */ { if ((zend_ulong)num <= 9) { |