summaryrefslogtreecommitdiff
path: root/Zend/zend_operators.c
diff options
context:
space:
mode:
Diffstat (limited to 'Zend/zend_operators.c')
-rw-r--r--Zend/zend_operators.c151
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) {