Signed-off-by: Paul Gofman pgofman@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 }
/***********************************************************************