]> granicus.if.org Git - php/commitdiff
Optimized php_stripslash with SSSE3 instr
authorXinchen Hui <laruence@gmail.com>
Wed, 21 Feb 2018 02:09:11 +0000 (10:09 +0800)
committerXinchen Hui <laruence@gmail.com>
Wed, 21 Feb 2018 02:09:11 +0000 (10:09 +0800)
ext/standard/php_string.h
ext/standard/string.c

index 6e3642c4acbea7d1e98fccea0c381614eeaa2e35..526ccbb90b7a7e6730120e75076a23eb33f4dccb 100644 (file)
@@ -130,11 +130,12 @@ PHPAPI zend_string *php_string_tolower(zend_string *s);
 PHPAPI char *php_strtr(char *str, size_t len, const char *str_from, const char *str_to, size_t trlen);
 #if ZEND_INTRIN_SSE4_2_FUNC_PTR
 PHPAPI extern zend_string *(*php_addslashes)(zend_string *str, int should_free);
+PHPAPI void (*php_stripslashes)(zend_string *str);
 #else
 PHPAPI zend_string *php_addslashes(zend_string *str, int should_free);
+PHPAPI void php_stripslashes(zend_string *str);
 #endif
 PHPAPI zend_string *php_addcslashes(zend_string *str, int freeit, char *what, size_t what_len);
-PHPAPI void php_stripslashes(zend_string *str);
 PHPAPI void php_stripcslashes(zend_string *str);
 PHPAPI zend_string *php_basename(const char *s, size_t len, char *suffix, size_t sufflen);
 PHPAPI size_t php_dirname(char *str, size_t len);
index c3af4050c2e2e3b2dca4a6ad1d645c3e010582a2..e45309af53a953c2373cf9af7b87cbe3ffa531fe 100644 (file)
@@ -3639,43 +3639,6 @@ PHP_FUNCTION(similar_text)
 }
 /* }}} */
 
-/* {{{ php_stripslashes
- *
- * be careful, this edits the string in-place */
-PHPAPI void php_stripslashes(zend_string *str)
-{
-       char *s, *t;
-       size_t l;
-
-       s = ZSTR_VAL(str);
-       t = ZSTR_VAL(str);
-       l = ZSTR_LEN(str);
-
-       while (l > 0) {
-               if (*t == '\\') {
-                       t++;                            /* skip the slash */
-                       ZSTR_LEN(str)--;
-                       l--;
-                       if (l > 0) {
-                               if (*t == '0') {
-                                       *s++='\0';
-                                       t++;
-                               } else {
-                                       *s++ = *t++;    /* preserve the next character */
-                               }
-                               l--;
-                       }
-               } else {
-                       *s++ = *t++;
-                       l--;
-               }
-       }
-       if (s != t) {
-               *s = '\0';
-       }
-}
-/* }}} */
-
 /* {{{ proto string addcslashes(string str, string charlist)
    Escapes all chars mentioned in charlist with backslash. It creates octal representations if asked to backslash characters with 8th bit set or with ASCII<32 (except '\n', '\r', '\t' etc...) */
 PHP_FUNCTION(addcslashes)
@@ -3887,8 +3850,12 @@ PHPAPI zend_string *php_addcslashes(zend_string *str, int should_free, char *wha
 ZEND_INTRIN_SSE4_2_FUNC_DECL(zend_string *php_addslashes_sse42(zend_string *str, int should_free));
 zend_string *php_addslashes_default(zend_string *str, int should_free);
 
+ZEND_INTRIN_SSE4_2_FUNC_DECL(void php_stripslashes_sse42(zend_string *str));
+void php_stripslashes_default(zend_string *str);
+
 # if ZEND_INTRIN_SSE4_2_FUNC_PROTO
 PHPAPI zend_string *php_addslashes(zend_string *str, int should_free) __attribute__((ifunc("resolve_addslashes")));
+PHPAPI void php_stripslashes(zend_string *str) __attribute__((ifunc("resolve_stripslashes")));
 
 static void *resolve_addslashes() {
        if (zend_cpu_supports_sse42()) {
@@ -3896,9 +3863,17 @@ static void *resolve_addslashes() {
        }
        return  php_addslashes_default;
 }
+
+static void *resolve_stripslashes() {
+       if (zend_cpu_supports_sse42()) {
+               return php_stripslashes_sse42;
+       }
+       return  php_stripslashes_default;
+}
 # else /* ZEND_INTRIN_SSE4_2_FUNC_PTR */
 
 PHPAPI zend_string *(*php_addslashes)(zend_string *str, int should_free) = NULL;
+PHPAPI void (*php_stripslashes)(zend_string *str) = NULL;
 
 /* {{{ PHP_MINIT_FUNCTION
  */
@@ -3906,8 +3881,10 @@ PHP_MINIT_FUNCTION(string_intrin)
 {
        if (zend_cpu_supports(ZEND_CPU_FEATURE_SSE42)) {
                php_addslashes = php_addslashes_sse42;
+               php_stripslashes = php_stripslashes_sse42;
        } else {
                php_addslashes = php_addslashes_default;
+               php_stripslashes = php_stripslashes_default;
        }
        return SUCCESS;
 }
@@ -4144,6 +4121,108 @@ do_escape:
 /* }}} */
 /* }}} */
 
+/* {{{ php_stripslashes
+ *
+ * be careful, this edits the string in-place */
+static zend_always_inline char *php_stripslashes_impl(const char *str, char *out, size_t len)
+{
+       while (len > 0) {
+               if (*str == '\\') {
+                       str++;                          /* skip the slash */
+                       len--;
+                       if (len > 0) {
+                               if (*str == '0') {
+                                       *out++='\0';
+                                       str++;
+                               } else {
+                                       *out++ = *str++;        /* preserve the next character */
+                               }
+                               len--;
+                       }
+               } else {
+                       *out++ = *str++;
+                       len--;
+               }
+       }
+
+       return out;
+}
+
+#if ZEND_INTRIN_SSE4_2_NATIVE || ZEND_INTRIN_SSE4_2_RESOLVER
+# if ZEND_INTRIN_SSE4_2_NATIVE
+PHPAPI void php_stripslashes(zend_string *str)
+# elif ZEND_INTRIN_SSE4_2_RESOLVER
+PHPAPI void php_stripslashes_sse42(zend_string *str)
+# endif
+{
+       const char *s = ZSTR_VAL(str);
+       char *t = ZSTR_VAL(str);
+       size_t l = ZSTR_LEN(str);
+
+       if (l > 15) {
+               const __m128i slash = _mm_set1_epi8('\\');
+
+               do {
+                       __m128i in = _mm_loadu_si128((__m128i *)s);
+                       __m128i any_slash = _mm_cmpeq_epi8(in, slash);
+                       uint32_t res = _mm_movemask_epi8(any_slash);
+
+                       if (res) {
+                               int i, n = zend_ulong_ntz(res);
+                               const char *e = s + 15;
+                               l -= n;
+                               for (i = 0; i < n; i++) {
+                                       *t++ = *s++;
+                               }
+                               for (; s < e; s++) {
+                                       if (*s == '\\') {
+                                               s++;
+                                               l--;
+                                               if (*s == '0') {
+                                                       *t = '\0';
+                                               } else {
+                                                       *t = *s;
+                                               }
+                                       } else {
+                                               *t = *s;
+                                       }
+                                       t++;
+                                       l--;
+                               }
+                       } else {
+                               _mm_storeu_si128((__m128i *)t, in);
+                               s += 16;
+                               t += 16;
+                               l -= 16;
+                       }
+               } while (l > 15);
+       }
+
+       t = php_stripslashes_impl(s, t, l);
+       if (t != (ZSTR_VAL(str) + ZSTR_LEN(str))) {
+               ZSTR_LEN(str) = t - ZSTR_VAL(str);
+               ZSTR_VAL(str)[ZSTR_LEN(str)] = '\0';
+       }
+}
+#endif
+
+#if !ZEND_INTRIN_SSE4_2_NATIVE
+# if ZEND_INTRIN_SSE4_2_RESOLVER
+void php_stripslashes_default(zend_string *str) /* {{{ */
+# else
+PHPAPI void php_stripslashes(zend_string *str)
+# endif
+{
+       char *t = php_stripslashes_impl(ZSTR_VAL(str), ZSTR_VAL(str), ZSTR_LEN(str));
+       if (t != (ZSTR_VAL(str) + ZSTR_LEN(str))) {
+               ZSTR_LEN(str) = t - ZSTR_VAL(str);
+               ZSTR_VAL(str)[ZSTR_LEN(str)] = '\0';
+       }
+}
+/* }}} */
+#endif
+/* }}} */
+
 #define _HEB_BLOCK_TYPE_ENG 1
 #define _HEB_BLOCK_TYPE_HEB 2
 #define isheb(c)      (((((unsigned char) c) >= 224) && (((unsigned char) c) <= 250)) ? 1 : 0)