Merge "<bits/threads_inlines.h>: add missing nullability annotations." into main
diff --git a/libc/bionic/icu_wrappers.cpp b/libc/bionic/icu_wrappers.cpp
index d9f2745..523f5a6 100644
--- a/libc/bionic/icu_wrappers.cpp
+++ b/libc/bionic/icu_wrappers.cpp
@@ -40,10 +40,3 @@
       reinterpret_cast<u_getIntPropertyValue_t>(__find_icu_symbol("u_getIntPropertyValue"));
   return u_getIntPropertyValue ? u_getIntPropertyValue(wc, property) : 0;
 }
-
-bool __icu_hasBinaryProperty(wint_t wc, UProperty property, int (*fallback)(int)) {
-  typedef UBool (*u_hasBinaryProperty_t)(UChar32, UProperty);
-  static auto u_hasBinaryProperty =
-      reinterpret_cast<u_hasBinaryProperty_t>(__find_icu_symbol("u_hasBinaryProperty"));
-  return u_hasBinaryProperty ? u_hasBinaryProperty(wc, property) : fallback(wc);
-}
diff --git a/libc/bionic/wctype.cpp b/libc/bionic/wctype.cpp
index 481197a..94597d9 100644
--- a/libc/bionic/wctype.cpp
+++ b/libc/bionic/wctype.cpp
@@ -54,26 +54,41 @@
   WC_TYPE_MAX
 };
 
-int iswalnum(wint_t wc) { return __icu_hasBinaryProperty(wc, UCHAR_POSIX_ALNUM, isalnum); }
+static u_hasBinaryProperty_t __find_u_hasBinaryProperty() {
+  static auto u_hasBinaryProperty =
+      reinterpret_cast<u_hasBinaryProperty_t>(__find_icu_symbol("u_hasBinaryProperty"));
+  return u_hasBinaryProperty;
+}
+
+#define DO_ISW(icu_constant, narrow_fn) \
+  u_hasBinaryProperty_t u_hasBinaryProperty; \
+  if (__predict_true(wc < 0x80) || \
+      !(u_hasBinaryProperty = __find_u_hasBinaryProperty())) { \
+    return narrow_fn(wc); \
+  } \
+  return u_hasBinaryProperty(wc, icu_constant); \
+
+int iswalnum(wint_t wc) { DO_ISW(UCHAR_POSIX_ALNUM, isalnum); }
 __strong_alias(iswalnum_l, iswalnum);
-int iswalpha(wint_t wc) { return __icu_hasBinaryProperty(wc, UCHAR_ALPHABETIC, isalpha); }
+int iswalpha(wint_t wc) { DO_ISW(UCHAR_ALPHABETIC, isalpha); }
 __strong_alias(iswalpha_l, iswalpha);
-int iswblank(wint_t wc) { return __icu_hasBinaryProperty(wc, UCHAR_POSIX_BLANK, isblank); }
+int iswblank(wint_t wc) { DO_ISW(UCHAR_POSIX_BLANK, isblank); }
 __strong_alias(iswblank_l, iswblank);
-int iswgraph(wint_t wc) { return __icu_hasBinaryProperty(wc, UCHAR_POSIX_GRAPH, isgraph); }
+int iswgraph(wint_t wc) { DO_ISW(UCHAR_POSIX_GRAPH, isgraph); }
 __strong_alias(iswgraph_l, iswgraph);
-int iswlower(wint_t wc) { return __icu_hasBinaryProperty(wc, UCHAR_LOWERCASE, islower); }
+int iswlower(wint_t wc) { DO_ISW(UCHAR_LOWERCASE, islower); }
 __strong_alias(iswlower_l, iswlower);
-int iswprint(wint_t wc) { return __icu_hasBinaryProperty(wc, UCHAR_POSIX_PRINT, isprint); }
+int iswprint(wint_t wc) { DO_ISW(UCHAR_POSIX_PRINT, isprint); }
 __strong_alias(iswprint_l, iswprint);
-int iswspace(wint_t wc) { return __icu_hasBinaryProperty(wc, UCHAR_WHITE_SPACE, isspace); }
+int iswspace(wint_t wc) { DO_ISW(UCHAR_WHITE_SPACE, isspace); }
 __strong_alias(iswspace_l, iswspace);
-int iswupper(wint_t wc) { return __icu_hasBinaryProperty(wc, UCHAR_UPPERCASE, isupper); }
+int iswupper(wint_t wc) { DO_ISW(UCHAR_UPPERCASE, isupper); }
 __strong_alias(iswupper_l, iswupper);
-int iswxdigit(wint_t wc) { return __icu_hasBinaryProperty(wc, UCHAR_POSIX_XDIGIT, isxdigit); }
+int iswxdigit(wint_t wc) { DO_ISW(UCHAR_POSIX_XDIGIT, isxdigit); }
 __strong_alias(iswxdigit_l, iswxdigit);
 
 int iswcntrl(wint_t wc) {
+  if (wc < 0x80) return iscntrl(wc);
   typedef int8_t (*FnT)(UChar32);
   static auto u_charType = reinterpret_cast<FnT>(__find_icu_symbol("u_charType"));
   return u_charType ? (u_charType(wc) == U_CONTROL_CHAR) : iscntrl(wc);
@@ -81,6 +96,7 @@
 __strong_alias(iswcntrl_l, iswcntrl);
 
 int iswdigit(wint_t wc) {
+  if (wc < 0x80) return isdigit(wc);
   typedef UBool (*FnT)(UChar32);
   static auto u_isdigit = reinterpret_cast<FnT>(__find_icu_symbol("u_isdigit"));
   return u_isdigit ? u_isdigit(wc) : isdigit(wc);
@@ -88,6 +104,7 @@
 __strong_alias(iswdigit_l, iswdigit);
 
 int iswpunct(wint_t wc) {
+  if (wc < 0x80) return ispunct(wc);
   typedef UBool (*FnT)(UChar32);
   static auto u_ispunct = reinterpret_cast<FnT>(__find_icu_symbol("u_ispunct"));
   return u_ispunct ? u_ispunct(wc) : ispunct(wc);
diff --git a/libc/bionic/wcwidth.cpp b/libc/bionic/wcwidth.cpp
index 4582ef7..776321f 100644
--- a/libc/bionic/wcwidth.cpp
+++ b/libc/bionic/wcwidth.cpp
@@ -73,7 +73,9 @@
 
   // Hangeul choseong filler U+115F is default ignorable, so we check default
   // ignorability only after we've already handled Hangeul jamo above.
-  if (__icu_hasBinaryProperty(wc, UCHAR_DEFAULT_IGNORABLE_CODE_POINT, nullptr)) return 0;
+  static auto u_hasBinaryProperty =
+      reinterpret_cast<u_hasBinaryProperty_t>(__find_icu_symbol("u_hasBinaryProperty"));
+  if (u_hasBinaryProperty && u_hasBinaryProperty(wc, UCHAR_DEFAULT_IGNORABLE_CODE_POINT)) return 0;
 
   // A few weird special cases where EastAsianWidth is not helpful for us.
   if (wc >= 0x3248 && wc <= 0x4dff) {
diff --git a/libc/private/icu.h b/libc/private/icu.h
index a671e98..8e4aa80 100644
--- a/libc/private/icu.h
+++ b/libc/private/icu.h
@@ -80,7 +80,8 @@
 
 int8_t __icu_charType(wint_t wc);
 int32_t __icu_getIntPropertyValue(wint_t wc, UProperty property);
-bool __icu_hasBinaryProperty(wint_t wc, UProperty property, int (*fallback)(int));
+
+typedef UBool (*u_hasBinaryProperty_t)(UChar32, UProperty);
 
 void* __find_icu_symbol(const char* symbol_name);
 
diff --git a/tests/Android.bp b/tests/Android.bp
index cfaeced..deb2843 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -566,12 +566,6 @@
     },
 
     generated_headers: ["generated_android_ids"],
-
-    // Bug: http://b/218788252 IR verifier too strict for ifunc resolver that
-    // accept parameters.
-    lto: {
-        never: true,
-    },
 }
 
 cc_test_library {
diff --git a/tests/libs/segment_gap_outer.cpp b/tests/libs/segment_gap_outer.cpp
index 3ba90d0..0328a99 100644
--- a/tests/libs/segment_gap_outer.cpp
+++ b/tests/libs/segment_gap_outer.cpp
@@ -1,6 +1,7 @@
 #include <android/dlext.h>
 #include <dlfcn.h>
 #include <stdlib.h>
+#include <unistd.h>
 
 extern "C" void __attribute__((section(".custom_text"))) text_before_start_of_gap() {}
 char __attribute__((section(".custom_bss"))) end_of_gap[0x1000];
@@ -10,8 +11,9 @@
   info.flags = ANDROID_DLEXT_RESERVED_ADDRESS;
 
   char* start_of_gap =
-      reinterpret_cast<char*>(reinterpret_cast<uintptr_t>(text_before_start_of_gap) & ~0xfffull) +
-      0x1000;
+      reinterpret_cast<char*>(
+          (reinterpret_cast<uintptr_t>(text_before_start_of_gap) &
+           ~(sysconf(_SC_PAGESIZE) - 1)) + sysconf(_SC_PAGESIZE));
   info.reserved_addr = start_of_gap;
   info.reserved_size = end_of_gap - start_of_gap;
 
diff --git a/tests/libs/segment_gap_outer.lds b/tests/libs/segment_gap_outer.lds
index 527f29e..758b6bc 100644
--- a/tests/libs/segment_gap_outer.lds
+++ b/tests/libs/segment_gap_outer.lds
@@ -3,17 +3,17 @@
   # appropriate alignment between them.
   . = SIZEOF_HEADERS;
   .rodata : {*(.rodata .rodata.*)}
-  . = ALIGN(0x1000);
+  . = ALIGN(CONSTANT (MAXPAGESIZE));
   .text : {*(.text .text.*)}
-  . = ALIGN(0x1000);
+  . = ALIGN(CONSTANT (MAXPAGESIZE));
   .dynamic : {*(.dynamic)}
-  . = ALIGN(0x1000);
+  . = ALIGN(CONSTANT (MAXPAGESIZE));
   .data : {*(.data .data.*)}
   .bss : {*(.bss .bss.*)}
 
   # Now create the gap. We need a text segment first to prevent the linker from
   # merging .bss with .custom_bss.
-  . = ALIGN(0x1000);
+  . = ALIGN(CONSTANT (MAXPAGESIZE));
   .custom_text : {
     *(.custom_text);
   }