Home | History | Annotate | Download | only in runtime
      1 // Copyright 2014 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 
      6 #ifdef V8_I18N_SUPPORT
      7 #include "src/runtime/runtime-utils.h"
      8 
      9 #include "src/api.h"
     10 #include "src/api-natives.h"
     11 #include "src/arguments.h"
     12 #include "src/factory.h"
     13 #include "src/i18n.h"
     14 #include "src/isolate-inl.h"
     15 #include "src/messages.h"
     16 
     17 #include "unicode/brkiter.h"
     18 #include "unicode/calendar.h"
     19 #include "unicode/coll.h"
     20 #include "unicode/curramt.h"
     21 #include "unicode/datefmt.h"
     22 #include "unicode/dcfmtsym.h"
     23 #include "unicode/decimfmt.h"
     24 #include "unicode/dtfmtsym.h"
     25 #include "unicode/dtptngen.h"
     26 #include "unicode/locid.h"
     27 #include "unicode/normalizer2.h"
     28 #include "unicode/numfmt.h"
     29 #include "unicode/numsys.h"
     30 #include "unicode/rbbi.h"
     31 #include "unicode/smpdtfmt.h"
     32 #include "unicode/timezone.h"
     33 #include "unicode/translit.h"
     34 #include "unicode/uchar.h"
     35 #include "unicode/ucol.h"
     36 #include "unicode/ucurr.h"
     37 #include "unicode/uloc.h"
     38 #include "unicode/unistr.h"
     39 #include "unicode/unum.h"
     40 #include "unicode/uversion.h"
     41 
     42 
     43 namespace v8 {
     44 namespace internal {
     45 namespace {
     46 
     47 const UChar* GetUCharBufferFromFlat(const String::FlatContent& flat,
     48                                     base::SmartArrayPointer<uc16>* dest,
     49                                     int32_t length) {
     50   DCHECK(flat.IsFlat());
     51   if (flat.IsOneByte()) {
     52     if (dest->is_empty()) {
     53       dest->Reset(NewArray<uc16>(length));
     54       CopyChars(dest->get(), flat.ToOneByteVector().start(), length);
     55     }
     56     return reinterpret_cast<const UChar*>(dest->get());
     57   } else {
     58     return reinterpret_cast<const UChar*>(flat.ToUC16Vector().start());
     59   }
     60 }
     61 
     62 }  // namespace
     63 
     64 RUNTIME_FUNCTION(Runtime_CanonicalizeLanguageTag) {
     65   HandleScope scope(isolate);
     66   Factory* factory = isolate->factory();
     67 
     68   DCHECK(args.length() == 1);
     69   CONVERT_ARG_HANDLE_CHECKED(String, locale_id_str, 0);
     70 
     71   v8::String::Utf8Value locale_id(v8::Utils::ToLocal(locale_id_str));
     72 
     73   // Return value which denotes invalid language tag.
     74   const char* const kInvalidTag = "invalid-tag";
     75 
     76   UErrorCode error = U_ZERO_ERROR;
     77   char icu_result[ULOC_FULLNAME_CAPACITY];
     78   int icu_length = 0;
     79 
     80   uloc_forLanguageTag(*locale_id, icu_result, ULOC_FULLNAME_CAPACITY,
     81                       &icu_length, &error);
     82   if (U_FAILURE(error) || icu_length == 0) {
     83     return *factory->NewStringFromAsciiChecked(kInvalidTag);
     84   }
     85 
     86   char result[ULOC_FULLNAME_CAPACITY];
     87 
     88   // Force strict BCP47 rules.
     89   uloc_toLanguageTag(icu_result, result, ULOC_FULLNAME_CAPACITY, TRUE, &error);
     90 
     91   if (U_FAILURE(error)) {
     92     return *factory->NewStringFromAsciiChecked(kInvalidTag);
     93   }
     94 
     95   return *factory->NewStringFromAsciiChecked(result);
     96 }
     97 
     98 
     99 RUNTIME_FUNCTION(Runtime_AvailableLocalesOf) {
    100   HandleScope scope(isolate);
    101   Factory* factory = isolate->factory();
    102 
    103   DCHECK(args.length() == 1);
    104   CONVERT_ARG_HANDLE_CHECKED(String, service, 0);
    105 
    106   const icu::Locale* available_locales = NULL;
    107   int32_t count = 0;
    108 
    109   if (service->IsUtf8EqualTo(CStrVector("collator"))) {
    110     available_locales = icu::Collator::getAvailableLocales(count);
    111   } else if (service->IsUtf8EqualTo(CStrVector("numberformat"))) {
    112     available_locales = icu::NumberFormat::getAvailableLocales(count);
    113   } else if (service->IsUtf8EqualTo(CStrVector("dateformat"))) {
    114     available_locales = icu::DateFormat::getAvailableLocales(count);
    115   } else if (service->IsUtf8EqualTo(CStrVector("breakiterator"))) {
    116     available_locales = icu::BreakIterator::getAvailableLocales(count);
    117   }
    118 
    119   UErrorCode error = U_ZERO_ERROR;
    120   char result[ULOC_FULLNAME_CAPACITY];
    121   Handle<JSObject> locales = factory->NewJSObject(isolate->object_function());
    122 
    123   for (int32_t i = 0; i < count; ++i) {
    124     const char* icu_name = available_locales[i].getName();
    125 
    126     error = U_ZERO_ERROR;
    127     // No need to force strict BCP47 rules.
    128     uloc_toLanguageTag(icu_name, result, ULOC_FULLNAME_CAPACITY, FALSE, &error);
    129     if (U_FAILURE(error)) {
    130       // This shouldn't happen, but lets not break the user.
    131       continue;
    132     }
    133 
    134     RETURN_FAILURE_ON_EXCEPTION(
    135         isolate, JSObject::SetOwnPropertyIgnoreAttributes(
    136                      locales, factory->NewStringFromAsciiChecked(result),
    137                      factory->NewNumber(i), NONE));
    138   }
    139 
    140   return *locales;
    141 }
    142 
    143 
    144 RUNTIME_FUNCTION(Runtime_GetDefaultICULocale) {
    145   HandleScope scope(isolate);
    146   Factory* factory = isolate->factory();
    147 
    148   DCHECK(args.length() == 0);
    149 
    150   icu::Locale default_locale;
    151 
    152   // Set the locale
    153   char result[ULOC_FULLNAME_CAPACITY];
    154   UErrorCode status = U_ZERO_ERROR;
    155   uloc_toLanguageTag(default_locale.getName(), result, ULOC_FULLNAME_CAPACITY,
    156                      FALSE, &status);
    157   if (U_SUCCESS(status)) {
    158     return *factory->NewStringFromAsciiChecked(result);
    159   }
    160 
    161   return *factory->NewStringFromStaticChars("und");
    162 }
    163 
    164 
    165 RUNTIME_FUNCTION(Runtime_GetLanguageTagVariants) {
    166   HandleScope scope(isolate);
    167   Factory* factory = isolate->factory();
    168 
    169   DCHECK(args.length() == 1);
    170 
    171   CONVERT_ARG_HANDLE_CHECKED(JSArray, input, 0);
    172 
    173   uint32_t length = static_cast<uint32_t>(input->length()->Number());
    174   // Set some limit to prevent fuzz tests from going OOM.
    175   // Can be bumped when callers' requirements change.
    176   RUNTIME_ASSERT(length < 100);
    177   Handle<FixedArray> output = factory->NewFixedArray(length);
    178   Handle<Name> maximized = factory->NewStringFromStaticChars("maximized");
    179   Handle<Name> base = factory->NewStringFromStaticChars("base");
    180   for (unsigned int i = 0; i < length; ++i) {
    181     Handle<Object> locale_id;
    182     ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
    183         isolate, locale_id, JSReceiver::GetElement(isolate, input, i));
    184     if (!locale_id->IsString()) {
    185       return isolate->Throw(*factory->illegal_argument_string());
    186     }
    187 
    188     v8::String::Utf8Value utf8_locale_id(
    189         v8::Utils::ToLocal(Handle<String>::cast(locale_id)));
    190 
    191     UErrorCode error = U_ZERO_ERROR;
    192 
    193     // Convert from BCP47 to ICU format.
    194     // de-DE-u-co-phonebk -> de_DE@collation=phonebook
    195     char icu_locale[ULOC_FULLNAME_CAPACITY];
    196     int icu_locale_length = 0;
    197     uloc_forLanguageTag(*utf8_locale_id, icu_locale, ULOC_FULLNAME_CAPACITY,
    198                         &icu_locale_length, &error);
    199     if (U_FAILURE(error) || icu_locale_length == 0) {
    200       return isolate->Throw(*factory->illegal_argument_string());
    201     }
    202 
    203     // Maximize the locale.
    204     // de_DE@collation=phonebook -> de_Latn_DE@collation=phonebook
    205     char icu_max_locale[ULOC_FULLNAME_CAPACITY];
    206     uloc_addLikelySubtags(icu_locale, icu_max_locale, ULOC_FULLNAME_CAPACITY,
    207                           &error);
    208 
    209     // Remove extensions from maximized locale.
    210     // de_Latn_DE@collation=phonebook -> de_Latn_DE
    211     char icu_base_max_locale[ULOC_FULLNAME_CAPACITY];
    212     uloc_getBaseName(icu_max_locale, icu_base_max_locale,
    213                      ULOC_FULLNAME_CAPACITY, &error);
    214 
    215     // Get original name without extensions.
    216     // de_DE@collation=phonebook -> de_DE
    217     char icu_base_locale[ULOC_FULLNAME_CAPACITY];
    218     uloc_getBaseName(icu_locale, icu_base_locale, ULOC_FULLNAME_CAPACITY,
    219                      &error);
    220 
    221     // Convert from ICU locale format to BCP47 format.
    222     // de_Latn_DE -> de-Latn-DE
    223     char base_max_locale[ULOC_FULLNAME_CAPACITY];
    224     uloc_toLanguageTag(icu_base_max_locale, base_max_locale,
    225                        ULOC_FULLNAME_CAPACITY, FALSE, &error);
    226 
    227     // de_DE -> de-DE
    228     char base_locale[ULOC_FULLNAME_CAPACITY];
    229     uloc_toLanguageTag(icu_base_locale, base_locale, ULOC_FULLNAME_CAPACITY,
    230                        FALSE, &error);
    231 
    232     if (U_FAILURE(error)) {
    233       return isolate->Throw(*factory->illegal_argument_string());
    234     }
    235 
    236     Handle<JSObject> result = factory->NewJSObject(isolate->object_function());
    237     Handle<String> value = factory->NewStringFromAsciiChecked(base_max_locale);
    238     JSObject::AddProperty(result, maximized, value, NONE);
    239     value = factory->NewStringFromAsciiChecked(base_locale);
    240     JSObject::AddProperty(result, base, value, NONE);
    241     output->set(i, *result);
    242   }
    243 
    244   Handle<JSArray> result = factory->NewJSArrayWithElements(output);
    245   result->set_length(Smi::FromInt(length));
    246   return *result;
    247 }
    248 
    249 
    250 RUNTIME_FUNCTION(Runtime_IsInitializedIntlObject) {
    251   HandleScope scope(isolate);
    252 
    253   DCHECK(args.length() == 1);
    254 
    255   CONVERT_ARG_HANDLE_CHECKED(Object, input, 0);
    256 
    257   if (!input->IsJSObject()) return isolate->heap()->false_value();
    258   Handle<JSObject> obj = Handle<JSObject>::cast(input);
    259 
    260   Handle<Symbol> marker = isolate->factory()->intl_initialized_marker_symbol();
    261   Handle<Object> tag = JSReceiver::GetDataProperty(obj, marker);
    262   return isolate->heap()->ToBoolean(!tag->IsUndefined(isolate));
    263 }
    264 
    265 
    266 RUNTIME_FUNCTION(Runtime_IsInitializedIntlObjectOfType) {
    267   HandleScope scope(isolate);
    268 
    269   DCHECK(args.length() == 2);
    270 
    271   CONVERT_ARG_HANDLE_CHECKED(Object, input, 0);
    272   CONVERT_ARG_HANDLE_CHECKED(String, expected_type, 1);
    273 
    274   if (!input->IsJSObject()) return isolate->heap()->false_value();
    275   Handle<JSObject> obj = Handle<JSObject>::cast(input);
    276 
    277   Handle<Symbol> marker = isolate->factory()->intl_initialized_marker_symbol();
    278   Handle<Object> tag = JSReceiver::GetDataProperty(obj, marker);
    279   return isolate->heap()->ToBoolean(tag->IsString() &&
    280                                     String::cast(*tag)->Equals(*expected_type));
    281 }
    282 
    283 
    284 RUNTIME_FUNCTION(Runtime_MarkAsInitializedIntlObjectOfType) {
    285   HandleScope scope(isolate);
    286 
    287   DCHECK(args.length() == 3);
    288 
    289   CONVERT_ARG_HANDLE_CHECKED(JSObject, input, 0);
    290   CONVERT_ARG_HANDLE_CHECKED(String, type, 1);
    291   CONVERT_ARG_HANDLE_CHECKED(JSObject, impl, 2);
    292 
    293   Handle<Symbol> marker = isolate->factory()->intl_initialized_marker_symbol();
    294   JSObject::SetProperty(input, marker, type, STRICT).Assert();
    295 
    296   marker = isolate->factory()->intl_impl_object_symbol();
    297   JSObject::SetProperty(input, marker, impl, STRICT).Assert();
    298 
    299   return isolate->heap()->undefined_value();
    300 }
    301 
    302 
    303 RUNTIME_FUNCTION(Runtime_GetImplFromInitializedIntlObject) {
    304   HandleScope scope(isolate);
    305 
    306   DCHECK(args.length() == 1);
    307 
    308   CONVERT_ARG_HANDLE_CHECKED(JSObject, input, 0);
    309 
    310   if (!input->IsJSObject()) {
    311     THROW_NEW_ERROR_RETURN_FAILURE(
    312         isolate, NewTypeError(MessageTemplate::kNotIntlObject, input));
    313   }
    314 
    315   Handle<JSObject> obj = Handle<JSObject>::cast(input);
    316 
    317   Handle<Symbol> marker = isolate->factory()->intl_impl_object_symbol();
    318 
    319   Handle<Object> impl = JSReceiver::GetDataProperty(obj, marker);
    320   if (impl->IsTheHole(isolate)) {
    321     THROW_NEW_ERROR_RETURN_FAILURE(
    322         isolate, NewTypeError(MessageTemplate::kNotIntlObject, obj));
    323   }
    324   return *impl;
    325 }
    326 
    327 
    328 RUNTIME_FUNCTION(Runtime_CreateDateTimeFormat) {
    329   HandleScope scope(isolate);
    330 
    331   DCHECK(args.length() == 3);
    332 
    333   CONVERT_ARG_HANDLE_CHECKED(String, locale, 0);
    334   CONVERT_ARG_HANDLE_CHECKED(JSObject, options, 1);
    335   CONVERT_ARG_HANDLE_CHECKED(JSObject, resolved, 2);
    336 
    337   Handle<ObjectTemplateInfo> date_format_template = I18N::GetTemplate(isolate);
    338 
    339   // Create an empty object wrapper.
    340   Handle<JSObject> local_object;
    341   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
    342       isolate, local_object,
    343       ApiNatives::InstantiateObject(date_format_template));
    344 
    345   // Set date time formatter as internal field of the resulting JS object.
    346   icu::SimpleDateFormat* date_format =
    347       DateFormat::InitializeDateTimeFormat(isolate, locale, options, resolved);
    348 
    349   if (!date_format) return isolate->ThrowIllegalOperation();
    350 
    351   local_object->SetInternalField(0, reinterpret_cast<Smi*>(date_format));
    352 
    353   Factory* factory = isolate->factory();
    354   Handle<String> key = factory->NewStringFromStaticChars("dateFormat");
    355   Handle<String> value = factory->NewStringFromStaticChars("valid");
    356   JSObject::AddProperty(local_object, key, value, NONE);
    357 
    358   // Make object handle weak so we can delete the data format once GC kicks in.
    359   Handle<Object> wrapper = isolate->global_handles()->Create(*local_object);
    360   GlobalHandles::MakeWeak(wrapper.location(), wrapper.location(),
    361                           DateFormat::DeleteDateFormat,
    362                           WeakCallbackType::kInternalFields);
    363   return *local_object;
    364 }
    365 
    366 
    367 RUNTIME_FUNCTION(Runtime_InternalDateFormat) {
    368   HandleScope scope(isolate);
    369 
    370   DCHECK(args.length() == 2);
    371 
    372   CONVERT_ARG_HANDLE_CHECKED(JSObject, date_format_holder, 0);
    373   CONVERT_ARG_HANDLE_CHECKED(JSDate, date, 1);
    374 
    375   Handle<Object> value;
    376   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value, Object::ToNumber(date));
    377 
    378   icu::SimpleDateFormat* date_format =
    379       DateFormat::UnpackDateFormat(isolate, date_format_holder);
    380   if (!date_format) return isolate->ThrowIllegalOperation();
    381 
    382   icu::UnicodeString result;
    383   date_format->format(value->Number(), result);
    384 
    385   RETURN_RESULT_OR_FAILURE(
    386       isolate, isolate->factory()->NewStringFromTwoByte(Vector<const uint16_t>(
    387                    reinterpret_cast<const uint16_t*>(result.getBuffer()),
    388                    result.length())));
    389 }
    390 
    391 
    392 RUNTIME_FUNCTION(Runtime_InternalDateParse) {
    393   HandleScope scope(isolate);
    394 
    395   DCHECK(args.length() == 2);
    396 
    397   CONVERT_ARG_HANDLE_CHECKED(JSObject, date_format_holder, 0);
    398   CONVERT_ARG_HANDLE_CHECKED(String, date_string, 1);
    399 
    400   v8::String::Utf8Value utf8_date(v8::Utils::ToLocal(date_string));
    401   icu::UnicodeString u_date(icu::UnicodeString::fromUTF8(*utf8_date));
    402   icu::SimpleDateFormat* date_format =
    403       DateFormat::UnpackDateFormat(isolate, date_format_holder);
    404   if (!date_format) return isolate->ThrowIllegalOperation();
    405 
    406   UErrorCode status = U_ZERO_ERROR;
    407   UDate date = date_format->parse(u_date, status);
    408   if (U_FAILURE(status)) return isolate->heap()->undefined_value();
    409 
    410   RETURN_RESULT_OR_FAILURE(
    411       isolate, JSDate::New(isolate->date_function(), isolate->date_function(),
    412                            static_cast<double>(date)));
    413 }
    414 
    415 
    416 RUNTIME_FUNCTION(Runtime_CreateNumberFormat) {
    417   HandleScope scope(isolate);
    418 
    419   DCHECK(args.length() == 3);
    420 
    421   CONVERT_ARG_HANDLE_CHECKED(String, locale, 0);
    422   CONVERT_ARG_HANDLE_CHECKED(JSObject, options, 1);
    423   CONVERT_ARG_HANDLE_CHECKED(JSObject, resolved, 2);
    424 
    425   Handle<ObjectTemplateInfo> number_format_template =
    426       I18N::GetTemplate(isolate);
    427 
    428   // Create an empty object wrapper.
    429   Handle<JSObject> local_object;
    430   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
    431       isolate, local_object,
    432       ApiNatives::InstantiateObject(number_format_template));
    433 
    434   // Set number formatter as internal field of the resulting JS object.
    435   icu::DecimalFormat* number_format =
    436       NumberFormat::InitializeNumberFormat(isolate, locale, options, resolved);
    437 
    438   if (!number_format) return isolate->ThrowIllegalOperation();
    439 
    440   local_object->SetInternalField(0, reinterpret_cast<Smi*>(number_format));
    441 
    442   Factory* factory = isolate->factory();
    443   Handle<String> key = factory->NewStringFromStaticChars("numberFormat");
    444   Handle<String> value = factory->NewStringFromStaticChars("valid");
    445   JSObject::AddProperty(local_object, key, value, NONE);
    446 
    447   Handle<Object> wrapper = isolate->global_handles()->Create(*local_object);
    448   GlobalHandles::MakeWeak(wrapper.location(), wrapper.location(),
    449                           NumberFormat::DeleteNumberFormat,
    450                           WeakCallbackType::kInternalFields);
    451   return *local_object;
    452 }
    453 
    454 
    455 RUNTIME_FUNCTION(Runtime_InternalNumberFormat) {
    456   HandleScope scope(isolate);
    457 
    458   DCHECK(args.length() == 2);
    459 
    460   CONVERT_ARG_HANDLE_CHECKED(JSObject, number_format_holder, 0);
    461   CONVERT_ARG_HANDLE_CHECKED(Object, number, 1);
    462 
    463   Handle<Object> value;
    464   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value, Object::ToNumber(number));
    465 
    466   icu::DecimalFormat* number_format =
    467       NumberFormat::UnpackNumberFormat(isolate, number_format_holder);
    468   if (!number_format) return isolate->ThrowIllegalOperation();
    469 
    470   icu::UnicodeString result;
    471   number_format->format(value->Number(), result);
    472 
    473   RETURN_RESULT_OR_FAILURE(
    474       isolate, isolate->factory()->NewStringFromTwoByte(Vector<const uint16_t>(
    475                    reinterpret_cast<const uint16_t*>(result.getBuffer()),
    476                    result.length())));
    477 }
    478 
    479 
    480 RUNTIME_FUNCTION(Runtime_InternalNumberParse) {
    481   HandleScope scope(isolate);
    482 
    483   DCHECK(args.length() == 2);
    484 
    485   CONVERT_ARG_HANDLE_CHECKED(JSObject, number_format_holder, 0);
    486   CONVERT_ARG_HANDLE_CHECKED(String, number_string, 1);
    487 
    488   isolate->CountUsage(v8::Isolate::UseCounterFeature::kIntlV8Parse);
    489 
    490   v8::String::Utf8Value utf8_number(v8::Utils::ToLocal(number_string));
    491   icu::UnicodeString u_number(icu::UnicodeString::fromUTF8(*utf8_number));
    492   icu::DecimalFormat* number_format =
    493       NumberFormat::UnpackNumberFormat(isolate, number_format_holder);
    494   if (!number_format) return isolate->ThrowIllegalOperation();
    495 
    496   UErrorCode status = U_ZERO_ERROR;
    497   icu::Formattable result;
    498   // ICU 4.6 doesn't support parseCurrency call. We need to wait for ICU49
    499   // to be part of Chrome.
    500   // TODO(cira): Include currency parsing code using parseCurrency call.
    501   // We need to check if the formatter parses all currencies or only the
    502   // one it was constructed with (it will impact the API - how to return ISO
    503   // code and the value).
    504   number_format->parse(u_number, result, status);
    505   if (U_FAILURE(status)) return isolate->heap()->undefined_value();
    506 
    507   switch (result.getType()) {
    508     case icu::Formattable::kDouble:
    509       return *isolate->factory()->NewNumber(result.getDouble());
    510     case icu::Formattable::kLong:
    511       return *isolate->factory()->NewNumberFromInt(result.getLong());
    512     case icu::Formattable::kInt64:
    513       return *isolate->factory()->NewNumber(
    514           static_cast<double>(result.getInt64()));
    515     default:
    516       return isolate->heap()->undefined_value();
    517   }
    518 }
    519 
    520 
    521 RUNTIME_FUNCTION(Runtime_CreateCollator) {
    522   HandleScope scope(isolate);
    523 
    524   DCHECK(args.length() == 3);
    525 
    526   CONVERT_ARG_HANDLE_CHECKED(String, locale, 0);
    527   CONVERT_ARG_HANDLE_CHECKED(JSObject, options, 1);
    528   CONVERT_ARG_HANDLE_CHECKED(JSObject, resolved, 2);
    529 
    530   Handle<ObjectTemplateInfo> collator_template = I18N::GetTemplate(isolate);
    531 
    532   // Create an empty object wrapper.
    533   Handle<JSObject> local_object;
    534   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
    535       isolate, local_object, ApiNatives::InstantiateObject(collator_template));
    536 
    537   // Set collator as internal field of the resulting JS object.
    538   icu::Collator* collator =
    539       Collator::InitializeCollator(isolate, locale, options, resolved);
    540 
    541   if (!collator) return isolate->ThrowIllegalOperation();
    542 
    543   local_object->SetInternalField(0, reinterpret_cast<Smi*>(collator));
    544 
    545   Factory* factory = isolate->factory();
    546   Handle<String> key = factory->NewStringFromStaticChars("collator");
    547   Handle<String> value = factory->NewStringFromStaticChars("valid");
    548   JSObject::AddProperty(local_object, key, value, NONE);
    549 
    550   Handle<Object> wrapper = isolate->global_handles()->Create(*local_object);
    551   GlobalHandles::MakeWeak(wrapper.location(), wrapper.location(),
    552                           Collator::DeleteCollator,
    553                           WeakCallbackType::kInternalFields);
    554   return *local_object;
    555 }
    556 
    557 
    558 RUNTIME_FUNCTION(Runtime_InternalCompare) {
    559   HandleScope scope(isolate);
    560 
    561   DCHECK(args.length() == 3);
    562 
    563   CONVERT_ARG_HANDLE_CHECKED(JSObject, collator_holder, 0);
    564   CONVERT_ARG_HANDLE_CHECKED(String, string1, 1);
    565   CONVERT_ARG_HANDLE_CHECKED(String, string2, 2);
    566 
    567   icu::Collator* collator = Collator::UnpackCollator(isolate, collator_holder);
    568   if (!collator) return isolate->ThrowIllegalOperation();
    569 
    570   string1 = String::Flatten(string1);
    571   string2 = String::Flatten(string2);
    572   DisallowHeapAllocation no_gc;
    573   int32_t length1 = string1->length();
    574   int32_t length2 = string2->length();
    575   String::FlatContent flat1 = string1->GetFlatContent();
    576   String::FlatContent flat2 = string2->GetFlatContent();
    577   base::SmartArrayPointer<uc16> sap1;
    578   base::SmartArrayPointer<uc16> sap2;
    579   const UChar* string_val1 = GetUCharBufferFromFlat(flat1, &sap1, length1);
    580   const UChar* string_val2 = GetUCharBufferFromFlat(flat2, &sap2, length2);
    581   UErrorCode status = U_ZERO_ERROR;
    582   UCollationResult result =
    583       collator->compare(string_val1, length1, string_val2, length2, status);
    584   if (U_FAILURE(status)) return isolate->ThrowIllegalOperation();
    585 
    586   return *isolate->factory()->NewNumberFromInt(result);
    587 }
    588 
    589 
    590 RUNTIME_FUNCTION(Runtime_StringNormalize) {
    591   HandleScope scope(isolate);
    592   static const struct {
    593     const char* name;
    594     UNormalization2Mode mode;
    595   } normalizationForms[] = {
    596       {"nfc", UNORM2_COMPOSE},
    597       {"nfc", UNORM2_DECOMPOSE},
    598       {"nfkc", UNORM2_COMPOSE},
    599       {"nfkc", UNORM2_DECOMPOSE},
    600   };
    601 
    602   DCHECK(args.length() == 2);
    603 
    604   CONVERT_ARG_HANDLE_CHECKED(String, s, 0);
    605   CONVERT_NUMBER_CHECKED(int, form_id, Int32, args[1]);
    606   RUNTIME_ASSERT(form_id >= 0 &&
    607                  static_cast<size_t>(form_id) < arraysize(normalizationForms));
    608 
    609   int length = s->length();
    610   s = String::Flatten(s);
    611   icu::UnicodeString result;
    612   base::SmartArrayPointer<uc16> sap;
    613   UErrorCode status = U_ZERO_ERROR;
    614   {
    615     DisallowHeapAllocation no_gc;
    616     String::FlatContent flat = s->GetFlatContent();
    617     const UChar* src = GetUCharBufferFromFlat(flat, &sap, length);
    618     icu::UnicodeString input(false, src, length);
    619     // Getting a singleton. Should not free it.
    620     const icu::Normalizer2* normalizer =
    621         icu::Normalizer2::getInstance(nullptr, normalizationForms[form_id].name,
    622                                       normalizationForms[form_id].mode, status);
    623     DCHECK(U_SUCCESS(status));
    624     RUNTIME_ASSERT(normalizer != nullptr);
    625     int32_t normalized_prefix_length =
    626         normalizer->spanQuickCheckYes(input, status);
    627     // Quick return if the input is already normalized.
    628     if (length == normalized_prefix_length) return *s;
    629     icu::UnicodeString unnormalized =
    630         input.tempSubString(normalized_prefix_length);
    631     // Read-only alias of the normalized prefix.
    632     result.setTo(false, input.getBuffer(), normalized_prefix_length);
    633     // copy-on-write; normalize the suffix and append to |result|.
    634     normalizer->normalizeSecondAndAppend(result, unnormalized, status);
    635   }
    636 
    637   if (U_FAILURE(status)) {
    638     return isolate->heap()->undefined_value();
    639   }
    640 
    641   RETURN_RESULT_OR_FAILURE(
    642       isolate, isolate->factory()->NewStringFromTwoByte(Vector<const uint16_t>(
    643                    reinterpret_cast<const uint16_t*>(result.getBuffer()),
    644                    result.length())));
    645 }
    646 
    647 
    648 RUNTIME_FUNCTION(Runtime_CreateBreakIterator) {
    649   HandleScope scope(isolate);
    650 
    651   DCHECK(args.length() == 3);
    652 
    653   CONVERT_ARG_HANDLE_CHECKED(String, locale, 0);
    654   CONVERT_ARG_HANDLE_CHECKED(JSObject, options, 1);
    655   CONVERT_ARG_HANDLE_CHECKED(JSObject, resolved, 2);
    656 
    657   Handle<ObjectTemplateInfo> break_iterator_template =
    658       I18N::GetTemplate2(isolate);
    659 
    660   // Create an empty object wrapper.
    661   Handle<JSObject> local_object;
    662   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
    663       isolate, local_object,
    664       ApiNatives::InstantiateObject(break_iterator_template));
    665 
    666   // Set break iterator as internal field of the resulting JS object.
    667   icu::BreakIterator* break_iterator = BreakIterator::InitializeBreakIterator(
    668       isolate, locale, options, resolved);
    669 
    670   if (!break_iterator) return isolate->ThrowIllegalOperation();
    671 
    672   local_object->SetInternalField(0, reinterpret_cast<Smi*>(break_iterator));
    673   // Make sure that the pointer to adopted text is NULL.
    674   local_object->SetInternalField(1, static_cast<Smi*>(nullptr));
    675 
    676   Factory* factory = isolate->factory();
    677   Handle<String> key = factory->NewStringFromStaticChars("breakIterator");
    678   Handle<String> value = factory->NewStringFromStaticChars("valid");
    679   JSObject::AddProperty(local_object, key, value, NONE);
    680 
    681   // Make object handle weak so we can delete the break iterator once GC kicks
    682   // in.
    683   Handle<Object> wrapper = isolate->global_handles()->Create(*local_object);
    684   GlobalHandles::MakeWeak(wrapper.location(), wrapper.location(),
    685                           BreakIterator::DeleteBreakIterator,
    686                           WeakCallbackType::kInternalFields);
    687   return *local_object;
    688 }
    689 
    690 
    691 RUNTIME_FUNCTION(Runtime_BreakIteratorAdoptText) {
    692   HandleScope scope(isolate);
    693 
    694   DCHECK(args.length() == 2);
    695 
    696   CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0);
    697   CONVERT_ARG_HANDLE_CHECKED(String, text, 1);
    698 
    699   icu::BreakIterator* break_iterator =
    700       BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder);
    701   if (!break_iterator) return isolate->ThrowIllegalOperation();
    702 
    703   icu::UnicodeString* u_text = reinterpret_cast<icu::UnicodeString*>(
    704       break_iterator_holder->GetInternalField(1));
    705   delete u_text;
    706 
    707   int length = text->length();
    708   text = String::Flatten(text);
    709   DisallowHeapAllocation no_gc;
    710   String::FlatContent flat = text->GetFlatContent();
    711   base::SmartArrayPointer<uc16> sap;
    712   const UChar* text_value = GetUCharBufferFromFlat(flat, &sap, length);
    713   u_text = new icu::UnicodeString(text_value, length);
    714   break_iterator_holder->SetInternalField(1, reinterpret_cast<Smi*>(u_text));
    715 
    716   break_iterator->setText(*u_text);
    717 
    718   return isolate->heap()->undefined_value();
    719 }
    720 
    721 
    722 RUNTIME_FUNCTION(Runtime_BreakIteratorFirst) {
    723   HandleScope scope(isolate);
    724 
    725   DCHECK(args.length() == 1);
    726 
    727   CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0);
    728 
    729   icu::BreakIterator* break_iterator =
    730       BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder);
    731   if (!break_iterator) return isolate->ThrowIllegalOperation();
    732 
    733   return *isolate->factory()->NewNumberFromInt(break_iterator->first());
    734 }
    735 
    736 
    737 RUNTIME_FUNCTION(Runtime_BreakIteratorNext) {
    738   HandleScope scope(isolate);
    739 
    740   DCHECK(args.length() == 1);
    741 
    742   CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0);
    743 
    744   icu::BreakIterator* break_iterator =
    745       BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder);
    746   if (!break_iterator) return isolate->ThrowIllegalOperation();
    747 
    748   return *isolate->factory()->NewNumberFromInt(break_iterator->next());
    749 }
    750 
    751 
    752 RUNTIME_FUNCTION(Runtime_BreakIteratorCurrent) {
    753   HandleScope scope(isolate);
    754 
    755   DCHECK(args.length() == 1);
    756 
    757   CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0);
    758 
    759   icu::BreakIterator* break_iterator =
    760       BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder);
    761   if (!break_iterator) return isolate->ThrowIllegalOperation();
    762 
    763   return *isolate->factory()->NewNumberFromInt(break_iterator->current());
    764 }
    765 
    766 
    767 RUNTIME_FUNCTION(Runtime_BreakIteratorBreakType) {
    768   HandleScope scope(isolate);
    769 
    770   DCHECK(args.length() == 1);
    771 
    772   CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0);
    773 
    774   icu::BreakIterator* break_iterator =
    775       BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder);
    776   if (!break_iterator) return isolate->ThrowIllegalOperation();
    777 
    778   // TODO(cira): Remove cast once ICU fixes base BreakIterator class.
    779   icu::RuleBasedBreakIterator* rule_based_iterator =
    780       static_cast<icu::RuleBasedBreakIterator*>(break_iterator);
    781   int32_t status = rule_based_iterator->getRuleStatus();
    782   // Keep return values in sync with JavaScript BreakType enum.
    783   if (status >= UBRK_WORD_NONE && status < UBRK_WORD_NONE_LIMIT) {
    784     return *isolate->factory()->NewStringFromStaticChars("none");
    785   } else if (status >= UBRK_WORD_NUMBER && status < UBRK_WORD_NUMBER_LIMIT) {
    786     return *isolate->factory()->number_string();
    787   } else if (status >= UBRK_WORD_LETTER && status < UBRK_WORD_LETTER_LIMIT) {
    788     return *isolate->factory()->NewStringFromStaticChars("letter");
    789   } else if (status >= UBRK_WORD_KANA && status < UBRK_WORD_KANA_LIMIT) {
    790     return *isolate->factory()->NewStringFromStaticChars("kana");
    791   } else if (status >= UBRK_WORD_IDEO && status < UBRK_WORD_IDEO_LIMIT) {
    792     return *isolate->factory()->NewStringFromStaticChars("ideo");
    793   } else {
    794     return *isolate->factory()->NewStringFromStaticChars("unknown");
    795   }
    796 }
    797 
    798 namespace {
    799 void ConvertCaseWithTransliterator(icu::UnicodeString* input,
    800                                    const char* transliterator_id) {
    801   UErrorCode status = U_ZERO_ERROR;
    802   base::SmartPointer<icu::Transliterator> translit(
    803       icu::Transliterator::createInstance(
    804           icu::UnicodeString(transliterator_id, -1, US_INV), UTRANS_FORWARD,
    805           status));
    806   if (U_FAILURE(status)) return;
    807   translit->transliterate(*input);
    808 }
    809 
    810 MUST_USE_RESULT Object* LocaleConvertCase(Handle<String> s, Isolate* isolate,
    811                                           bool is_to_upper, const char* lang) {
    812   int32_t src_length = s->length();
    813 
    814   // Greek uppercasing has to be done via transliteration.
    815   // TODO(jshin): Drop this special-casing once ICU's regular case conversion
    816   // API supports Greek uppercasing. See
    817   // http://bugs.icu-project.org/trac/ticket/10582 .
    818   // In the meantime, if there's no Greek character in |s|, call this
    819   // function again with the root locale (lang="").
    820   // ICU's C API for transliteration is nasty and we just use C++ API.
    821   if (V8_UNLIKELY(is_to_upper && lang[0] == 'e' && lang[1] == 'l')) {
    822     icu::UnicodeString converted;
    823     base::SmartArrayPointer<uc16> sap;
    824     {
    825       DisallowHeapAllocation no_gc;
    826       String::FlatContent flat = s->GetFlatContent();
    827       const UChar* src = GetUCharBufferFromFlat(flat, &sap, src_length);
    828       // Starts with the source string (read-only alias with copy-on-write
    829       // semantics) and will be modified to contain the converted result.
    830       // Using read-only alias at first saves one copy operation if
    831       // transliteration does not change the input, which is rather rare.
    832       // Moreover, transliteration takes rather long so that saving one copy
    833       // helps only a little bit.
    834       converted.setTo(false, src, src_length);
    835       ConvertCaseWithTransliterator(&converted, "el-Upper");
    836       // If no change is made, just return |s|.
    837       if (converted.getBuffer() == src) return *s;
    838     }
    839     RETURN_RESULT_OR_FAILURE(
    840         isolate,
    841         isolate->factory()->NewStringFromTwoByte(Vector<const uint16_t>(
    842             reinterpret_cast<const uint16_t*>(converted.getBuffer()),
    843             converted.length())));
    844   }
    845 
    846   auto case_converter = is_to_upper ? u_strToUpper : u_strToLower;
    847 
    848   int32_t dest_length = src_length;
    849   UErrorCode status;
    850   Handle<SeqTwoByteString> result;
    851   base::SmartArrayPointer<uc16> sap;
    852 
    853   // This is not a real loop. It'll be executed only once (no overflow) or
    854   // twice (overflow).
    855   for (int i = 0; i < 2; ++i) {
    856     result =
    857         isolate->factory()->NewRawTwoByteString(dest_length).ToHandleChecked();
    858     DisallowHeapAllocation no_gc;
    859     String::FlatContent flat = s->GetFlatContent();
    860     const UChar* src = GetUCharBufferFromFlat(flat, &sap, src_length);
    861     status = U_ZERO_ERROR;
    862     dest_length = case_converter(reinterpret_cast<UChar*>(result->GetChars()),
    863                                  dest_length, src, src_length, lang, &status);
    864     if (status != U_BUFFER_OVERFLOW_ERROR) break;
    865   }
    866 
    867   // In most cases, the output will fill the destination buffer completely
    868   // leading to an unterminated string (U_STRING_NOT_TERMINATED_WARNING).
    869   // Only in rare cases, it'll be shorter than the destination buffer and
    870   // |result| has to be truncated.
    871   DCHECK(U_SUCCESS(status));
    872   if (V8_LIKELY(status == U_STRING_NOT_TERMINATED_WARNING)) {
    873     DCHECK(dest_length == result->length());
    874     return *result;
    875   }
    876   if (U_SUCCESS(status)) {
    877     DCHECK(dest_length < result->length());
    878     return *Handle<SeqTwoByteString>::cast(
    879         SeqString::Truncate(result, dest_length));
    880   }
    881   return *s;
    882 }
    883 
    884 inline bool IsASCIIUpper(uint16_t ch) { return ch >= 'A' && ch <= 'Z'; }
    885 
    886 const uint8_t kToLower[256] = {
    887     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B,
    888     0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
    889     0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23,
    890     0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
    891     0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B,
    892     0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
    893     0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73,
    894     0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
    895     0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B,
    896     0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
    897     0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83,
    898     0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
    899     0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B,
    900     0x9C, 0x9D, 0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,
    901     0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3,
    902     0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
    903     0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB,
    904     0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xD7,
    905     0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xDF, 0xE0, 0xE1, 0xE2, 0xE3,
    906     0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
    907     0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB,
    908     0xFC, 0xFD, 0xFE, 0xFF,
    909 };
    910 
    911 inline uint16_t ToLatin1Lower(uint16_t ch) {
    912   return static_cast<uint16_t>(kToLower[ch]);
    913 }
    914 
    915 inline uint16_t ToASCIIUpper(uint16_t ch) {
    916   return ch & ~((ch >= 'a' && ch <= 'z') << 5);
    917 }
    918 
    919 // Does not work for U+00DF (sharp-s), U+00B5 (micron), U+00FF.
    920 inline uint16_t ToLatin1Upper(uint16_t ch) {
    921   DCHECK(ch != 0xDF && ch != 0xB5 && ch != 0xFF);
    922   return ch &
    923          ~(((ch >= 'a' && ch <= 'z') || (((ch & 0xE0) == 0xE0) && ch != 0xE7))
    924            << 5);
    925 }
    926 
    927 template <typename Char>
    928 bool ToUpperFastASCII(const Vector<const Char>& src,
    929                       Handle<SeqOneByteString> result) {
    930   // Do a faster loop for the case where all the characters are ASCII.
    931   uint16_t ored = 0;
    932   int32_t index = 0;
    933   for (auto it = src.begin(); it != src.end(); ++it) {
    934     uint16_t ch = static_cast<uint16_t>(*it);
    935     ored |= ch;
    936     result->SeqOneByteStringSet(index++, ToASCIIUpper(ch));
    937   }
    938   return !(ored & ~0x7F);
    939 }
    940 
    941 const uint16_t sharp_s = 0xDF;
    942 
    943 template <typename Char>
    944 bool ToUpperOneByte(const Vector<const Char>& src,
    945                     Handle<SeqOneByteString> result, int* sharp_s_count) {
    946   // Still pretty-fast path for the input with non-ASCII Latin-1 characters.
    947 
    948   // There are two special cases.
    949   //  1. U+00B5 and U+00FF are mapped to a character beyond U+00FF.
    950   //  2. Lower case sharp-S converts to "SS" (two characters)
    951   *sharp_s_count = 0;
    952   int32_t index = 0;
    953   for (auto it = src.begin(); it != src.end(); ++it) {
    954     uint16_t ch = static_cast<uint16_t>(*it);
    955     if (V8_UNLIKELY(ch == sharp_s)) {
    956       ++(*sharp_s_count);
    957       continue;
    958     }
    959     if (V8_UNLIKELY(ch == 0xB5 || ch == 0xFF)) {
    960       // Since this upper-cased character does not fit in an 8-bit string, we
    961       // need to take the 16-bit path.
    962       return false;
    963     }
    964     result->SeqOneByteStringSet(index++, ToLatin1Upper(ch));
    965   }
    966 
    967   return true;
    968 }
    969 
    970 template <typename Char>
    971 void ToUpperWithSharpS(const Vector<const Char>& src,
    972                        Handle<SeqOneByteString> result) {
    973   int32_t dest_index = 0;
    974   for (auto it = src.begin(); it != src.end(); ++it) {
    975     uint16_t ch = static_cast<uint16_t>(*it);
    976     if (ch == sharp_s) {
    977       result->SeqOneByteStringSet(dest_index++, 'S');
    978       result->SeqOneByteStringSet(dest_index++, 'S');
    979     } else {
    980       result->SeqOneByteStringSet(dest_index++, ToLatin1Upper(ch));
    981     }
    982   }
    983 }
    984 
    985 }  // namespace
    986 
    987 RUNTIME_FUNCTION(Runtime_StringToLowerCaseI18N) {
    988   HandleScope scope(isolate);
    989   DCHECK_EQ(args.length(), 1);
    990   CONVERT_ARG_HANDLE_CHECKED(String, s, 0);
    991 
    992   int length = s->length();
    993   s = String::Flatten(s);
    994   // First scan the string for uppercase and non-ASCII characters:
    995   if (s->HasOnlyOneByteChars()) {
    996     unsigned first_index_to_lower = length;
    997     for (int index = 0; index < length; ++index) {
    998       // Blink specializes this path for one-byte strings, so it
    999       // does not need to do a generic get, but can do the equivalent
   1000       // of SeqOneByteStringGet.
   1001       uint16_t ch = s->Get(index);
   1002       if (V8_UNLIKELY(IsASCIIUpper(ch) || ch & ~0x7F)) {
   1003         first_index_to_lower = index;
   1004         break;
   1005       }
   1006     }
   1007 
   1008     // Nothing to do if the string is all ASCII with no uppercase.
   1009     if (first_index_to_lower == length) return *s;
   1010 
   1011     // We depend here on the invariant that the length of a Latin1
   1012     // string is invariant under ToLowerCase, and the result always
   1013     // fits in the Latin1 range in the *root locale*. It does not hold
   1014     // for ToUpperCase even in the root locale.
   1015     Handle<SeqOneByteString> result;
   1016     ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
   1017         isolate, result, isolate->factory()->NewRawOneByteString(length));
   1018 
   1019     DisallowHeapAllocation no_gc;
   1020     String::FlatContent flat = s->GetFlatContent();
   1021     if (flat.IsOneByte()) {
   1022       const uint8_t* src = flat.ToOneByteVector().start();
   1023       CopyChars(result->GetChars(), src, first_index_to_lower);
   1024       for (int index = first_index_to_lower; index < length; ++index) {
   1025         uint16_t ch = static_cast<uint16_t>(src[index]);
   1026         result->SeqOneByteStringSet(index, ToLatin1Lower(ch));
   1027       }
   1028     } else {
   1029       const uint16_t* src = flat.ToUC16Vector().start();
   1030       CopyChars(result->GetChars(), src, first_index_to_lower);
   1031       for (int index = first_index_to_lower; index < length; ++index) {
   1032         uint16_t ch = src[index];
   1033         result->SeqOneByteStringSet(index, ToLatin1Lower(ch));
   1034       }
   1035     }
   1036 
   1037     return *result;
   1038   }
   1039 
   1040   // Blink had an additional case here for ASCII 2-byte strings, but
   1041   // that is subsumed by the above code (assuming there isn't a false
   1042   // negative for HasOnlyOneByteChars).
   1043 
   1044   // Do a slower implementation for cases that include non-ASCII characters.
   1045   return LocaleConvertCase(s, isolate, false, "");
   1046 }
   1047 
   1048 RUNTIME_FUNCTION(Runtime_StringToUpperCaseI18N) {
   1049   HandleScope scope(isolate);
   1050   DCHECK_EQ(args.length(), 1);
   1051   CONVERT_ARG_HANDLE_CHECKED(String, s, 0);
   1052 
   1053   // This function could be optimized for no-op cases the way lowercase
   1054   // counterpart is, but in empirical testing, few actual calls to upper()
   1055   // are no-ops. So, it wouldn't be worth the extra time for pre-scanning.
   1056 
   1057   int32_t length = s->length();
   1058   s = String::Flatten(s);
   1059 
   1060   if (s->HasOnlyOneByteChars()) {
   1061     Handle<SeqOneByteString> result;
   1062     ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
   1063         isolate, result, isolate->factory()->NewRawOneByteString(length));
   1064 
   1065     int sharp_s_count;
   1066     bool is_result_single_byte;
   1067     {
   1068       DisallowHeapAllocation no_gc;
   1069       String::FlatContent flat = s->GetFlatContent();
   1070       // If it was ok to slow down ASCII-only input slightly, ToUpperFastASCII
   1071       // could be removed  because ToUpperOneByte is pretty fast now (it
   1072       // does not call ICU API any more.).
   1073       if (flat.IsOneByte()) {
   1074         Vector<const uint8_t> src = flat.ToOneByteVector();
   1075         if (ToUpperFastASCII(src, result)) return *result;
   1076         is_result_single_byte = ToUpperOneByte(src, result, &sharp_s_count);
   1077       } else {
   1078         DCHECK(flat.IsTwoByte());
   1079         Vector<const uint16_t> src = flat.ToUC16Vector();
   1080         if (ToUpperFastASCII(src, result)) return *result;
   1081         is_result_single_byte = ToUpperOneByte(src, result, &sharp_s_count);
   1082       }
   1083     }
   1084 
   1085     // Go to the full Unicode path if there are characters whose uppercase
   1086     // is beyond the Latin-1 range (cannot be represented in OneByteString).
   1087     if (V8_UNLIKELY(!is_result_single_byte)) {
   1088       return LocaleConvertCase(s, isolate, true, "");
   1089     }
   1090 
   1091     if (sharp_s_count == 0) return *result;
   1092 
   1093     // We have sharp_s_count sharp-s characters, but the result is still
   1094     // in the Latin-1 range.
   1095     ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
   1096         isolate, result,
   1097         isolate->factory()->NewRawOneByteString(length + sharp_s_count));
   1098     DisallowHeapAllocation no_gc;
   1099     String::FlatContent flat = s->GetFlatContent();
   1100     if (flat.IsOneByte()) {
   1101       ToUpperWithSharpS(flat.ToOneByteVector(), result);
   1102     } else {
   1103       ToUpperWithSharpS(flat.ToUC16Vector(), result);
   1104     }
   1105 
   1106     return *result;
   1107   }
   1108 
   1109   return LocaleConvertCase(s, isolate, true, "");
   1110 }
   1111 
   1112 RUNTIME_FUNCTION(Runtime_StringLocaleConvertCase) {
   1113   HandleScope scope(isolate);
   1114   DCHECK_EQ(args.length(), 3);
   1115   CONVERT_ARG_HANDLE_CHECKED(String, s, 0);
   1116   CONVERT_BOOLEAN_ARG_CHECKED(is_upper, 1);
   1117   CONVERT_ARG_HANDLE_CHECKED(SeqOneByteString, lang, 2);
   1118 
   1119   // All the languages requiring special handling ("az", "el", "lt", "tr")
   1120   // have a 2-letter language code.
   1121   DCHECK(lang->length() == 2);
   1122   uint8_t lang_str[3];
   1123   memcpy(lang_str, lang->GetChars(), 2);
   1124   lang_str[2] = 0;
   1125   s = String::Flatten(s);
   1126   // TODO(jshin): Consider adding a fast path for ASCII or Latin-1. The fastpath
   1127   // in the root locale needs to be adjusted for az, lt and tr because even case
   1128   // mapping of ASCII range characters are different in those locales.
   1129   // Greek (el) does not require any adjustment, though.
   1130   return LocaleConvertCase(s, isolate, is_upper,
   1131                            reinterpret_cast<const char*>(lang_str));
   1132 }
   1133 
   1134 RUNTIME_FUNCTION(Runtime_DateCacheVersion) {
   1135   HandleScope scope(isolate);
   1136   DCHECK_EQ(0, args.length());
   1137   if (isolate->serializer_enabled()) return isolate->heap()->undefined_value();
   1138   if (!isolate->eternal_handles()->Exists(EternalHandles::DATE_CACHE_VERSION)) {
   1139     Handle<FixedArray> date_cache_version =
   1140         isolate->factory()->NewFixedArray(1, TENURED);
   1141     date_cache_version->set(0, Smi::FromInt(0));
   1142     isolate->eternal_handles()->CreateSingleton(
   1143         isolate, *date_cache_version, EternalHandles::DATE_CACHE_VERSION);
   1144   }
   1145   Handle<FixedArray> date_cache_version =
   1146       Handle<FixedArray>::cast(isolate->eternal_handles()->GetSingleton(
   1147           EternalHandles::DATE_CACHE_VERSION));
   1148   return date_cache_version->get(0);
   1149 }
   1150 
   1151 }  // namespace internal
   1152 }  // namespace v8
   1153 
   1154 #endif  // V8_I18N_SUPPORT
   1155