From 45cd713ef9ad40440ff2e530f38eac8ccb05ba14 Mon Sep 17 00:00:00 2001 From: Luke Gorrie Date: Wed, 3 Jan 2018 13:04:56 +0000 Subject: [PATCH] lj_str.c: Remove special-case string interning fastpath lj_str_new() had a separate fast-path and slow-path. This was bad because (a) the fast-path was complex and (b) the fast-path was actually slower than the slow-path in practice and (c) in practice it could cause confusing performance problems depending on the memory alignment of any often-reused string buffers in a program. This change specifically makes the 'life' benchmark faster and more robust to memory layout. --- .gitignore | 1 - ...special-case-string-interning-fastpa.patch | 83 +++++++++++++++++++ vendor/luajit/src/lj_str.c | 47 ++--------- 3 files changed, 90 insertions(+), 41 deletions(-) create mode 100644 vendor/luajit/0001-lj_str.c-Remove-special-case-string-interning-fastpa.patch diff --git a/.gitignore b/.gitignore index 9ec70c35f..107c3b93b 100644 --- a/.gitignore +++ b/.gitignore @@ -22,7 +22,6 @@ *.obj *.opensdf *.orig -*.patch *.pch *.pdb *.profdata diff --git a/vendor/luajit/0001-lj_str.c-Remove-special-case-string-interning-fastpa.patch b/vendor/luajit/0001-lj_str.c-Remove-special-case-string-interning-fastpa.patch new file mode 100644 index 000000000..4a6a47c00 --- /dev/null +++ b/vendor/luajit/0001-lj_str.c-Remove-special-case-string-interning-fastpa.patch @@ -0,0 +1,83 @@ +From fcf86b84772735a3195af034d0bc7ed0f4106337 Mon Sep 17 00:00:00 2001 +From: Luke Gorrie +Date: Wed, 3 Jan 2018 13:04:56 +0000 +Subject: [PATCH] lj_str.c: Remove special-case string interning fastpath + +lj_str_new() had a separate fast-path and slow-path. This was bad +because (a) the fast-path was complex and (b) the fast-path was +actually slower than the slow-path in practice and (c) in practice it +could cause confusing performance problems depending on the memory +alignment of any often-reused string buffers in a program. + +This change specifically makes the 'life' benchmark faster and more +robust to memory layout. +--- + src/lj_str.c | 47 +++++++---------------------------------------- + 1 file changed, 7 insertions(+), 40 deletions(-) + +diff --git a/src/lj_str.c b/src/lj_str.c +index b32d1398..d8f314ae 100644 +--- a/src/lj_str.c ++++ b/src/lj_str.c +@@ -37,27 +37,6 @@ int32_t lj_str_cmp(GCstr *a, GCstr *b) + return (int32_t)(a->len - b->len); + } + +-/* Fast string data comparison. Caveat: unaligned access to 1st string! */ +-static LJ_AINLINE int str_fastcmp(const char *a, const char *b, MSize len) +-{ +- MSize i = 0; +- lua_assert(len > 0); +- lua_assert((((uintptr_t)a+len-1) & (LJ_PAGESIZE-1)) <= LJ_PAGESIZE-4); +- do { /* Note: innocuous access up to end of string + 3. */ +- uint32_t v = lj_getu32(a+i) ^ *(const uint32_t *)(b+i); +- if (v) { +- i -= len; +-#if LJ_LE +- return (int32_t)i >= -3 ? (v << (32+(i<<3))) : 1; +-#else +- return (int32_t)i >= -3 ? (v >> (32+(i<<3))) : 1; +-#endif +- } +- i += 4; +- } while (i < len); +- return 0; +-} +- + /* Find fixed string p inside string s. */ + const char *lj_str_find(const char *s, const char *p, MSize slen, MSize plen) + { +@@ -149,26 +128,14 @@ GCstr *lj_str_new(lua_State *L, const char *str, size_t lenx) + h ^= b; h -= lj_rol(b, 16); + /* Check if the string has already been interned. */ + o = gcref(g->strhash[h & g->strmask]); +- if (LJ_LIKELY((((uintptr_t)str+len-1) & (LJ_PAGESIZE-1)) <= LJ_PAGESIZE-4)) { +- while (o != NULL) { +- GCstr *sx = gco2str(o); +- if (sx->len == len && str_fastcmp(str, strdata(sx), len) == 0) { +- /* Resurrect if dead. Can only happen with fixstring() (keywords). */ +- if (isdead(g, o)) flipwhite(o); +- return sx; /* Return existing string. */ +- } +- o = gcnext(o); +- } +- } else { /* Slow path: end of string is too close to a page boundary. */ +- while (o != NULL) { +- GCstr *sx = gco2str(o); +- if (sx->len == len && memcmp(str, strdata(sx), len) == 0) { +- /* Resurrect if dead. Can only happen with fixstring() (keywords). */ +- if (isdead(g, o)) flipwhite(o); +- return sx; /* Return existing string. */ +- } +- o = gcnext(o); ++ while (o != NULL) { ++ GCstr *sx = gco2str(o); ++ if (sx->len == len && memcmp(str, strdata(sx), len) == 0) { ++ /* Resurrect if dead. Can only happen with fixstring() (keywords). */ ++ if (isdead(g, o)) flipwhite(o); ++ return sx; /* Return existing string. */ + } ++ o = gcnext(o); + } + /* Nope, create a new string. */ + s = lj_mem_newt(L, sizeof(GCstr)+len+1, GCstr); diff --git a/vendor/luajit/src/lj_str.c b/vendor/luajit/src/lj_str.c index ca60bccb7..1d5a1efd7 100644 --- a/vendor/luajit/src/lj_str.c +++ b/vendor/luajit/src/lj_str.c @@ -43,27 +43,6 @@ int32_t LJ_FASTCALL lj_str_cmp(GCstr *a, GCstr *b) return (int32_t)(a->len - b->len); } -/* Fast string data comparison. Caveat: unaligned access to 1st string! */ -static LJ_AINLINE int str_fastcmp(const char *a, const char *b, MSize len) -{ - MSize i = 0; - lua_assert(len > 0); - lua_assert((((uintptr_t)a+len-1) & (LJ_PAGESIZE-1)) <= LJ_PAGESIZE-4); - do { /* Note: innocuous access up to end of string + 3. */ - uint32_t v = lj_getu32(a+i) ^ *(const uint32_t *)(b+i); - if (v) { - i -= len; -#if LJ_LE - return (int32_t)i >= -3 ? (v << (32+(i<<3))) : 1; -#else - return (int32_t)i >= -3 ? (v >> (32+(i<<3))) : 1; -#endif - } - i += 4; - } while (i < len); - return 0; -} - /* Resize the string hash table (grow and shrink). */ void lj_str_resize(lua_State *L, MSize newmask) { @@ -121,26 +100,14 @@ GCstr *lj_str_new(lua_State *L, const char *str, size_t lenx) h ^= b; h -= lj_rol(b, 16); /* Check if the string has already been interned. */ o = gcref(g->strhash[h & g->strmask]); - if (LJ_LIKELY((((uintptr_t)str+len-1) & (LJ_PAGESIZE-1)) <= LJ_PAGESIZE-4)) { - while (o != NULL) { - GCstr *sx = gco2str(o); - if (sx->len == len && str_fastcmp(str, strdata(sx), len) == 0) { - /* Resurrect if dead. Can only happen with fixstring() (keywords). */ - if (isdead(g, o)) flipwhite(o); - return sx; /* Return existing string. */ - } - o = gcnext(o); - } - } else { /* Slow path: end of string is too close to a page boundary. */ - while (o != NULL) { - GCstr *sx = gco2str(o); - if (sx->len == len && memcmp(str, strdata(sx), len) == 0) { - /* Resurrect if dead. Can only happen with fixstring() (keywords). */ - if (isdead(g, o)) flipwhite(o); - return sx; /* Return existing string. */ - } - o = gcnext(o); + while (o != NULL) { + GCstr *sx = gco2str(o); + if (sx->len == len && memcmp(str, strdata(sx), len) == 0) { + /* Resurrect if dead. Can only happen with fixstring() (keywords). */ + if (isdead(g, o)) flipwhite(o); + return sx; /* Return existing string. */ } + o = gcnext(o); } /* Nope, create a new string. */ s = lj_mem_newt(L, sizeof(GCstr)+len+1, GCstr);