Skip to content

Instantly share code, notes, and snippets.

@laruence
Created January 13, 2018 11:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save laruence/ddc916122cbf26faffeace0942a71d71 to your computer and use it in GitHub Desktop.
Save laruence/ddc916122cbf26faffeace0942a71d71 to your computer and use it in GitHub Desktop.
diff --git a/ext/standard/string.c b/ext/standard/string.c
index 97a20fb..d6b039f 100644
--- a/ext/standard/string.c
+++ b/ext/standard/string.c
@@ -34,6 +34,12 @@
#ifdef HAVE_MONETARY_H
# include <monetary.h>
#endif
+
+#ifdef __SSE4_2__
+#include <nmmintrin.h>
+#include "Zend/zend_bitset.h"
+#endif
+
/*
* This define is here because some versions of libintl redefine setlocale
* to point to libintl_setlocale. That's a ridiculous thing to do as far
@@ -3872,6 +3878,11 @@ PHPAPI zend_string *php_addslashes(zend_string *str, int should_free)
char *end;
size_t offset;
zend_string *new_str;
+#ifdef __SSE4_2__
+ uint32_t r = 0;
+ static const char ctrs[16] = "\'\"\\\0";
+ __m128i w, s;
+#endif
if (!str) {
return ZSTR_EMPTY_ALLOC();
@@ -3880,6 +3891,37 @@ PHPAPI zend_string *php_addslashes(zend_string *str, int should_free)
source = ZSTR_VAL(str);
end = source + ZSTR_LEN(str);
+#ifdef __SSE4_2__
+ if (ZSTR_LEN(str) > 15) {
+ char *align = (char*)(((uintptr_t)source + 15) & ~15);
+ w = _mm_load_si128((__m128i *)&ctrs[0]);
+
+ if (UNEXPECTED(source != align)) {
+ do {
+ switch (*source) {
+ case '\0':
+ case '\'':
+ case '\"':
+ case '\\':
+ goto do_escape;
+ default:
+ source++;
+ break;
+ }
+ } while (source < align);
+ }
+
+ for (;end - source > 15; source += 16) {
+ s = _mm_load_si128((__m128i *)source);
+ int r = _mm_cvtsi128_si32(
+ _mm_cmpestrm(w, 4, s, 16, _SIDD_UBYTE_OPS|_SIDD_CMP_EQUAL_ANY|_SIDD_BIT_MASK));
+ if (r) {
+ goto do_escape;
+ }
+ }
+ }
+#endif
+
while (source < end) {
switch (*source) {
case '\0':
@@ -3905,6 +3947,79 @@ do_escape:
memcpy(ZSTR_VAL(new_str), ZSTR_VAL(str), offset);
target = ZSTR_VAL(new_str) + offset;
+#ifdef __SSE4_2__
+ if (r) {
+ int pos = 0;
+ do {
+ int i, n = zend_ulong_ntz(r);
+ for (i = 0; i < n; i++) {
+ *target++ = source[pos + i];
+ }
+ pos += n;
+ *target++ = '\\';
+ if (source[pos] == '\0') {
+ *target++ = '0';
+ } else {
+ *target++ = source[pos];
+ }
+ pos++;
+ r = r >> (n + 1);
+ } while (r);
+
+ for (; pos < 16; pos++) {
+ *target++ = source[pos];
+ }
+ } else if (end - source > 15) {
+ char *align = (char*)(((zend_uintptr_t)source + 15) & ~15);
+ w = _mm_load_si128((__m128i *)&ctrs[0]);
+
+ if (source != align) {
+ do {
+ switch (*source) {
+ case '\0':
+ *target++ = '\\';
+ *target++ = '0';
+ break;
+ case '\'':
+ case '\"':
+ case '\\':
+ *target++ = '\\';
+ /* break is missing *intentionally* */
+ default:
+ *target++ = *source;
+ break;
+ }
+ source++;
+ } while (source < align);
+ }
+ }
+
+ for (; end - source > 15; source += 16) {
+ s = _mm_load_si128((__m128i *)source);
+ int r = _mm_cvtsi128_si32(
+ _mm_cmpestrm(w, 4, s, 16, _SIDD_UBYTE_OPS|_SIDD_CMP_EQUAL_ANY|_SIDD_BIT_MASK));
+ int pos = 0;
+ while (r) {
+ int i, n = zend_ulong_ntz(r);
+ r = r >> (n + 1);
+ for (i = 0; i < n; i++) {
+ *target++ = source[pos + i];
+ }
+ pos += n;
+ *target++ = '\\';
+ if (source[pos] == '\0') {
+ *target++ = '0';
+ } else {
+ *target++ = source[pos];
+ }
+ pos++;
+ }
+ for (; pos < 16; pos++) {
+ *target++ = source[pos];
+ }
+ }
+
+#endif
while (source < end) {
switch (*source) {
case '\0':
@@ -3920,11 +4035,10 @@ do_escape:
*target++ = *source;
break;
}
-
source++;
}
- *target = 0;
+ *target = '\0';
if (should_free) {
zend_string_release(str);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment