[PATCH v6 3/3] ntdll: Optimize get_vprot_range_size() for big ranges.
Paul Gofman
pgofman at codeweavers.com
Thu Sep 23 10:20:06 CDT 2021
Signed-off-by: Paul Gofman <pgofman at codeweavers.com>
---
v5:
- simplify the code:
- get rid of allocated vprot bytes range check since the function is
called for the ranges within views only for which the vprot bytes
should always be allocated;
- get rid of a few variables and one #ifdef straightening up a bit page index
handling on 64;
- renamed 'i' to 'curr_idx';
dlls/ntdll/unix/virtual.c | 53 +++++++++++++++++++++++++++++++++------
1 file changed, 46 insertions(+), 7 deletions(-)
diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c
index dfabd770509..9377c21cfc3 100644
--- a/dlls/ntdll/unix/virtual.c
+++ b/dlls/ntdll/unix/virtual.c
@@ -948,17 +948,56 @@ static BYTE get_page_vprot( const void *addr )
*
* Return the size of the region with equal masked vprot byte.
* Also return the protections for the first page.
- * The function assumes that base and size are page aligned and
- * base + size does not wrap around. */
+ * base and size should be page aligned.
+ * The function assumes that base and size are page aligned,
+ * base + size does not wrap around and the range is within view so
+ * vprot bytes are allocated for the range. */
static SIZE_T get_vprot_range_size( char *base, SIZE_T size, BYTE mask, BYTE *vprot )
{
- char *addr;
+#define BYTES_IN_WORD sizeof(UINT_PTR)
+ static const UINT_PTR word_from_byte = (UINT_PTR)0x101010101010101;
+ static const UINT_PTR index_align_mask = BYTES_IN_WORD - 1;
+ SIZE_T curr_idx, start_idx, end_idx, aligned_start_idx;
+ UINT_PTR vprot_word, mask_word;
+ const BYTE *vprot_ptr;
- *vprot = get_page_vprot( base );
- for (addr = base + page_size; addr != base + size; addr += page_size)
- if ((*vprot ^ get_page_vprot( addr )) & mask) break;
+ TRACE("base %p, size %p, mask %#x.\n", base, (void *)size, mask);
- return addr - base;
+ curr_idx = start_idx = (size_t)base >> page_shift;
+ end_idx = start_idx + (size >> page_shift);
+
+ aligned_start_idx = (start_idx + index_align_mask) & ~index_align_mask;
+ if (aligned_start_idx > end_idx) aligned_start_idx = end_idx;
+
+#ifdef _WIN64
+ vprot_ptr = pages_vprot[curr_idx >> pages_vprot_shift] + (curr_idx & pages_vprot_mask);
+#else
+ vprot_ptr = pages_vprot + curr_idx;
+#endif
+ *vprot = *vprot_ptr;
+
+ /* Page count page table is at least the multiples of BYTES_IN_WORD
+ * so we don't have to worry about crossing the boundary on unaligned idx values. */
+
+ for (; curr_idx < aligned_start_idx; ++curr_idx, ++vprot_ptr)
+ if ((*vprot ^ *vprot_ptr) & mask) return (curr_idx - start_idx) << page_shift;
+
+ vprot_word = word_from_byte * *vprot;
+ mask_word = word_from_byte * mask;
+ for (; curr_idx < end_idx; curr_idx += BYTES_IN_WORD, vprot_ptr += BYTES_IN_WORD)
+ {
+#ifdef _WIN64
+ if (!(curr_idx & pages_vprot_mask)) vprot_ptr = pages_vprot[curr_idx >> pages_vprot_shift];
+#endif
+ if ((vprot_word ^ *(UINT_PTR *)vprot_ptr) & mask_word)
+ {
+ for (; curr_idx < end_idx; ++curr_idx, ++vprot_ptr)
+ if ((*vprot ^ *vprot_ptr) & mask) break;
+ return (curr_idx - start_idx) << page_shift;
+ }
+ }
+ return size;
+#undef BYTES_IN_WORD
}
/***********************************************************************
--
2.31.1
More information about the wine-devel
mailing list