[runtime] Speed up String::IsOneByte

Check uintptr_t sized blocks of UTF16 chars at a time similar to NonAsciiStart.

Change-Id: Ib4c498cc064e6ac7b6f8cc87ab700eafc8132c39
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1622107
Commit-Queue: Toon Verwaest <verwaest@chromium.org>
Reviewed-by: Igor Sheludko <ishell@chromium.org>
Cr-Commit-Position: refs/heads/master@{#61693}
diff --git a/src/objects/string.h b/src/objects/string.h
index 1f05d79..7cdd6b8 100644
--- a/src/objects/string.h
+++ b/src/objects/string.h
@@ -381,12 +381,40 @@
   }
 
   static inline int NonOneByteStart(const uc16* chars, int length) {
-    const uc16* limit = chars + length;
-    const uc16* start = chars;
-    while (chars < limit) {
-      if (*chars > kMaxOneByteCharCodeU) return static_cast<int>(chars - start);
+    DCHECK(IsAligned(reinterpret_cast<Address>(chars), sizeof(uc16)));
+    const uint16_t* start = chars;
+    const uint16_t* limit = chars + length;
+
+    // Check unaligned chars.
+    while (!IsAligned(reinterpret_cast<Address>(chars), kUIntptrSize)) {
+      if (*chars > unibrow::Latin1::kMaxChar) {
+        return static_cast<int>(chars - start);
+      }
       ++chars;
     }
+
+    // Check aligned words.
+    STATIC_ASSERT(unibrow::Latin1::kMaxChar == 0xFF);
+#ifdef V8_TARGET_LITTLE_ENDIAN
+    const uintptr_t non_one_byte_mask = kUintptrAllBitsSet / 0xFFFF * 0xFF00;
+#else
+    const uintptr_t non_one_byte_mask = kUintptrAllBitsSet / 0xFFFF * 0x00FF;
+#endif
+    while (chars + sizeof(uintptr_t) <= limit) {
+      if (*reinterpret_cast<const uintptr_t*>(chars) & non_one_byte_mask) {
+        break;
+      }
+      chars += (sizeof(uintptr_t) / sizeof(uc16));
+    }
+
+    // Check remaining unaligned chars, or find non-one-byte char in word.
+    while (chars < limit) {
+      if (*chars > unibrow::Latin1::kMaxChar) {
+        return static_cast<int>(chars - start);
+      }
+      ++chars;
+    }
+
     return static_cast<int>(chars - start);
   }