Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1054)

Unified Diff: src/runtime/runtime-strings.cc

Issue 1812673005: Use ICU case conversion/transliterator for case conversion behind a flag (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Use CharCopy(); GetFlatContent still crashes Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/flag-definitions.h ('k') | test/intl/general/case-mapping.js » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/runtime/runtime-strings.cc
diff --git a/src/runtime/runtime-strings.cc b/src/runtime/runtime-strings.cc
index 6786fa99fba0f92e1c41e5e228d9f6852349dd74..656372eb09e5cbbb8be6d7623024bb5cb4bfb981 100644
--- a/src/runtime/runtime-strings.cc
+++ b/src/runtime/runtime-strings.cc
@@ -12,6 +12,12 @@
#include "src/string-builder.h"
#include "src/string-search.h"
+#ifdef V8_I18N_SUPPORT
+#include "unicode/locid.h"
+#include "unicode/uchar.h"
+#include "unicode/unistr.h"
+#endif
+
namespace v8 {
namespace internal {
@@ -1077,20 +1083,211 @@ MUST_USE_RESULT static Object* ConvertCase(
return ConvertCaseHelper(isolate, *s, *result, length, mapping);
}
+#ifdef V8_I18N_SUPPORT
+namespace {
+
+MUST_USE_RESULT static Handle<String> ConvertCaseICU(Handle<String> s,
+ Isolate* isolate,
+ bool is_to_upper) {
+ DCHECK(s->IsFlat());
+ // Handle<String> flattened = String::Flatten(s);
+ String::FlatContent flat = s->GetFlatContent();
jungshik at Google 2016/04/07 18:57:11 This leads to a assertion failure in objects.cc:
+
+ const UChar* src;
+ if (flat.IsOneByte()) {
+ base::SmartArrayPointer<uc16> sap = s->ToWideCString();
+ src = reinterpret_cast<const UChar*>(sap.get());
+ } else {
+ src = reinterpret_cast<const UChar*>(flat.ToUC16Vector().start());
+ }
+
+ int32_t length = s->length();
+
+ // This UnicodeString ctor has copy-on-write semantics. It starts as a
+ // read-only alias but the buffer is copied when it's written to.
+ icu::UnicodeString converted(0, src, length);
+ const icu::Locale& root_locale = icu::Locale::getRoot();
+ if (is_to_upper)
+ converted.toUpper(root_locale);
+ else
+ converted.toLower(root_locale);
+
+ return isolate->factory()
+ ->NewStringFromTwoByte(Vector<const uint16_t>(
+ reinterpret_cast<const uint16_t*>(converted.getBuffer()),
+ converted.length()))
+ .ToHandleChecked();
+}
+
+inline bool IsASCIIUpper(uint16_t ch) { return ch >= 'A' && ch <= 'Z'; }
+
+inline uint16_t ToASCIILower(uint16_t ch) {
+ return ch | ((ch >= 'A' && ch <= 'Z') << 5);
+}
+
+inline uint16_t ToASCIIUpper(uint16_t ch) {
+ return ch & ~((ch >= 'a' && ch <= 'z') << 5);
+}
+
+MUST_USE_RESULT Handle<String> StringToLowerCase(Handle<String> s,
+ Isolate* isolate) {
+ // Note: This is a hot function in the Dromaeo benchmark, specifically the
+ // no-op code path up through the first 'return' statement.
+
+ int length = s->length();
+ s = String::Flatten(s);
+ // First scan the string for uppercase and non-ASCII characters:
+ if (s->HasOnlyOneByteChars()) {
+ unsigned first_index_to_lower = length;
+ for (int index = 0; index < length; ++index) {
+ // Blink specializes this path for one-byte strings, so it
+ // does not need to do a generic get, but can do the equivalent
+ // of SeqOneByteStringGet.
+ uint16_t ch = s->Get(index);
+ if (V8_UNLIKELY(IsASCIIUpper(ch) || ch & ~0x7F)) {
+ first_index_to_lower = index;
+ break;
+ }
+ }
+
+ // Nothing to do if the string is all ASCII with no uppercase.
+ if (first_index_to_lower == length) return s;
+
+ // We depend here on the invariant that the length of a Latin1
+ // string is invariant under ToLowerCase, and the result always
+ // fits in the Latin1 range (untrue for ToUpperCase, and might
+ // be untrue in some locales, but this is the root locale)
+ Handle<SeqOneByteString> result =
+ isolate->factory()->NewRawOneByteString(length).ToHandleChecked();
+ if (s->IsSeqOneByteString()) {
+ SeqOneByteString* source = SeqOneByteString::cast(*s);
+ CopyChars(result->GetChars(), source->GetChars(), first_index_to_lower);
+ } else {
+ // Do we have to worry about External{One,Two}ByteString?
+ DCHECK(s->IsSeqTwoByteString());
+ SeqTwoByteString* source = SeqTwoByteString::cast(*s);
+ CopyChars(result->GetChars(), source->GetChars(), first_index_to_lower);
+ }
+
+ for (int index = first_index_to_lower; index < length; ++index) {
+ uint16_t ch = s->Get(index);
+ result->SeqOneByteStringSet(
+ index, V8_UNLIKELY(ch & ~0x7F) ? static_cast<uint16_t>(u_tolower(ch))
+ : ToASCIILower(ch));
+ }
+
+ return Handle<String>(*result);
+ }
+
+ // Blink had an additional case here for ASCII 2-byte strings, but
+ // that is subsumed by the above code (assuming there isn't a false
+ // negative for HasOnlyOneByteChars).
+
+ // Do a slower implementation for cases that include non-ASCII characters.
+ return ConvertCaseICU(s, isolate, false);
+}
+
+const uint16_t sharp_s = 0x00DFu;
+
+MUST_USE_RESULT Handle<String> StringToUpperCase(Handle<String> s,
+ Isolate* isolate) {
+ // This function could be optimized for no-op cases the way lower() is,
+ // but in empirical testing, few actual calls to upper() are no-ops, so
+ // it wouldn't be worth the extra time for pre-scanning.
+
+ int32_t length = s->length();
+ s = String::Flatten(s);
+
+ if (s->HasOnlyOneByteChars()) {
+ Handle<SeqOneByteString> result =
+ isolate->factory()->NewRawOneByteString(length).ToHandleChecked();
+
+ // Do a faster loop for the case where all the characters are ASCII.
+ uint16_t ored = 0;
+ for (int index = 0; index < length; ++index) {
+ uint16_t ch = s->Get(index);
+ ored |= ch;
+ result->SeqOneByteStringSet(index, ToASCIIUpper(ch));
+ }
+ if (!(ored & ~0x7F)) return Handle<String>(*result);
+
+ // Do a slower implementation for cases that include non-ASCII Latin-1
+ // characters.
+ int sharp_s_count = 0;
+
+ // There are two special cases.
+ // 1. latin-1 characters when converted to upper case are 16 bit
+ // characters.
+ // 2. Lower case sharp-S converts to "SS" (two characters)
+ for (int32_t index = 0; index < length; ++index) {
+ uint16_t ch = s->Get(index);
+ if (V8_UNLIKELY(ch == sharp_s)) {
+ ++sharp_s_count;
+ continue;
+ }
+ uint16_t upper = static_cast<uint16_t>(u_toupper(static_cast<UChar>(ch)));
+ if (V8_UNLIKELY(upper > 0xff)) {
+ // Since this upper-cased character does not fit in an 8-bit string, we
+ // need to take the 16-bit path.
+ goto upconvert;
+ }
+ result->SeqOneByteStringSet(index, upper);
+ }
+
+ if (sharp_s_count == 0) return Handle<String>(*result);
+
+ // We have sharp_s_count sharp-s characters, but none of the other special
+ // characters.
+ result = isolate->factory()
+ ->NewRawOneByteString(length + sharp_s_count)
+ .ToHandleChecked();
+ for (int32_t index = 0, dest_index = 0; index < length; ++index) {
+ uint16_t ch = s->Get(index);
+ if (ch == sharp_s) {
+ result->SeqOneByteStringSet(dest_index++, 'S');
+ result->SeqOneByteStringSet(dest_index++, 'S');
+ } else {
+ uint16_t upper =
+ static_cast<uint16_t>(u_toupper(static_cast<UChar>(ch)));
+ result->SeqOneByteStringSet(dest_index++, upper);
+ }
+ }
+
+ return Handle<String>(*result);
+ }
+
+upconvert:
+ return ConvertCaseICU(s, isolate, true);
+}
+
+} // namespace
+#endif
RUNTIME_FUNCTION(Runtime_StringToLowerCase) {
HandleScope scope(isolate);
- DCHECK(args.length() == 1);
+ DCHECK_EQ(args.length(), 1);
CONVERT_ARG_HANDLE_CHECKED(String, s, 0);
- return ConvertCase(s, isolate, isolate->runtime_state()->to_lower_mapping());
+#ifdef V8_I18N_SUPPORT
+ if (FLAG_icu_case_mapping)
+ return *StringToLowerCase(s, isolate);
+ else
+#endif
+ return ConvertCase(s, isolate,
+ isolate->runtime_state()->to_lower_mapping());
}
RUNTIME_FUNCTION(Runtime_StringToUpperCase) {
HandleScope scope(isolate);
- DCHECK(args.length() == 1);
+ DCHECK_EQ(args.length(), 1);
CONVERT_ARG_HANDLE_CHECKED(String, s, 0);
- return ConvertCase(s, isolate, isolate->runtime_state()->to_upper_mapping());
+#ifdef V8_I18N_SUPPORT
+ if (FLAG_icu_case_mapping)
+ return *StringToUpperCase(s, isolate);
+ else
+#endif
+ return ConvertCase(s, isolate,
+ isolate->runtime_state()->to_upper_mapping());
}
« no previous file with comments | « src/flag-definitions.h ('k') | test/intl/general/case-mapping.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698