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/numfmt.h"
     28 #include "unicode/numsys.h"
     29 #include "unicode/rbbi.h"
     30 #include "unicode/smpdtfmt.h"
     31 #include "unicode/timezone.h"
     32 #include "unicode/uchar.h"
     33 #include "unicode/ucol.h"
     34 #include "unicode/ucurr.h"
     35 #include "unicode/uloc.h"
     36 #include "unicode/unum.h"
     37 #include "unicode/uversion.h"
     38 
     39 
     40 namespace v8 {
     41 namespace internal {
     42 
     43 RUNTIME_FUNCTION(Runtime_CanonicalizeLanguageTag) {
     44   HandleScope scope(isolate);
     45   Factory* factory = isolate->factory();
     46 
     47   DCHECK(args.length() == 1);
     48   CONVERT_ARG_HANDLE_CHECKED(String, locale_id_str, 0);
     49 
     50   v8::String::Utf8Value locale_id(v8::Utils::ToLocal(locale_id_str));
     51 
     52   // Return value which denotes invalid language tag.
     53   const char* const kInvalidTag = "invalid-tag";
     54 
     55   UErrorCode error = U_ZERO_ERROR;
     56   char icu_result[ULOC_FULLNAME_CAPACITY];
     57   int icu_length = 0;
     58 
     59   uloc_forLanguageTag(*locale_id, icu_result, ULOC_FULLNAME_CAPACITY,
     60                       &icu_length, &error);
     61   if (U_FAILURE(error) || icu_length == 0) {
     62     return *factory->NewStringFromAsciiChecked(kInvalidTag);
     63   }
     64 
     65   char result[ULOC_FULLNAME_CAPACITY];
     66 
     67   // Force strict BCP47 rules.
     68   uloc_toLanguageTag(icu_result, result, ULOC_FULLNAME_CAPACITY, TRUE, &error);
     69 
     70   if (U_FAILURE(error)) {
     71     return *factory->NewStringFromAsciiChecked(kInvalidTag);
     72   }
     73 
     74   return *factory->NewStringFromAsciiChecked(result);
     75 }
     76 
     77 
     78 RUNTIME_FUNCTION(Runtime_AvailableLocalesOf) {
     79   HandleScope scope(isolate);
     80   Factory* factory = isolate->factory();
     81 
     82   DCHECK(args.length() == 1);
     83   CONVERT_ARG_HANDLE_CHECKED(String, service, 0);
     84 
     85   const icu::Locale* available_locales = NULL;
     86   int32_t count = 0;
     87 
     88   if (service->IsUtf8EqualTo(CStrVector("collator"))) {
     89     available_locales = icu::Collator::getAvailableLocales(count);
     90   } else if (service->IsUtf8EqualTo(CStrVector("numberformat"))) {
     91     available_locales = icu::NumberFormat::getAvailableLocales(count);
     92   } else if (service->IsUtf8EqualTo(CStrVector("dateformat"))) {
     93     available_locales = icu::DateFormat::getAvailableLocales(count);
     94   } else if (service->IsUtf8EqualTo(CStrVector("breakiterator"))) {
     95     available_locales = icu::BreakIterator::getAvailableLocales(count);
     96   }
     97 
     98   UErrorCode error = U_ZERO_ERROR;
     99   char result[ULOC_FULLNAME_CAPACITY];
    100   Handle<JSObject> locales = factory->NewJSObject(isolate->object_function());
    101 
    102   for (int32_t i = 0; i < count; ++i) {
    103     const char* icu_name = available_locales[i].getName();
    104 
    105     error = U_ZERO_ERROR;
    106     // No need to force strict BCP47 rules.
    107     uloc_toLanguageTag(icu_name, result, ULOC_FULLNAME_CAPACITY, FALSE, &error);
    108     if (U_FAILURE(error)) {
    109       // This shouldn't happen, but lets not break the user.
    110       continue;
    111     }
    112 
    113     RETURN_FAILURE_ON_EXCEPTION(
    114         isolate, JSObject::SetOwnPropertyIgnoreAttributes(
    115                      locales, factory->NewStringFromAsciiChecked(result),
    116                      factory->NewNumber(i), NONE));
    117   }
    118 
    119   return *locales;
    120 }
    121 
    122 
    123 RUNTIME_FUNCTION(Runtime_GetDefaultICULocale) {
    124   HandleScope scope(isolate);
    125   Factory* factory = isolate->factory();
    126 
    127   DCHECK(args.length() == 0);
    128 
    129   icu::Locale default_locale;
    130 
    131   // Set the locale
    132   char result[ULOC_FULLNAME_CAPACITY];
    133   UErrorCode status = U_ZERO_ERROR;
    134   uloc_toLanguageTag(default_locale.getName(), result, ULOC_FULLNAME_CAPACITY,
    135                      FALSE, &status);
    136   if (U_SUCCESS(status)) {
    137     return *factory->NewStringFromAsciiChecked(result);
    138   }
    139 
    140   return *factory->NewStringFromStaticChars("und");
    141 }
    142 
    143 
    144 RUNTIME_FUNCTION(Runtime_GetLanguageTagVariants) {
    145   HandleScope scope(isolate);
    146   Factory* factory = isolate->factory();
    147 
    148   DCHECK(args.length() == 1);
    149 
    150   CONVERT_ARG_HANDLE_CHECKED(JSArray, input, 0);
    151 
    152   uint32_t length = static_cast<uint32_t>(input->length()->Number());
    153   // Set some limit to prevent fuzz tests from going OOM.
    154   // Can be bumped when callers' requirements change.
    155   RUNTIME_ASSERT(length < 100);
    156   Handle<FixedArray> output = factory->NewFixedArray(length);
    157   Handle<Name> maximized = factory->NewStringFromStaticChars("maximized");
    158   Handle<Name> base = factory->NewStringFromStaticChars("base");
    159   for (unsigned int i = 0; i < length; ++i) {
    160     Handle<Object> locale_id;
    161     ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, locale_id,
    162                                        Object::GetElement(isolate, input, i));
    163     if (!locale_id->IsString()) {
    164       return isolate->Throw(*factory->illegal_argument_string());
    165     }
    166 
    167     v8::String::Utf8Value utf8_locale_id(
    168         v8::Utils::ToLocal(Handle<String>::cast(locale_id)));
    169 
    170     UErrorCode error = U_ZERO_ERROR;
    171 
    172     // Convert from BCP47 to ICU format.
    173     // de-DE-u-co-phonebk -> de_DE@collation=phonebook
    174     char icu_locale[ULOC_FULLNAME_CAPACITY];
    175     int icu_locale_length = 0;
    176     uloc_forLanguageTag(*utf8_locale_id, icu_locale, ULOC_FULLNAME_CAPACITY,
    177                         &icu_locale_length, &error);
    178     if (U_FAILURE(error) || icu_locale_length == 0) {
    179       return isolate->Throw(*factory->illegal_argument_string());
    180     }
    181 
    182     // Maximize the locale.
    183     // de_DE@collation=phonebook -> de_Latn_DE@collation=phonebook
    184     char icu_max_locale[ULOC_FULLNAME_CAPACITY];
    185     uloc_addLikelySubtags(icu_locale, icu_max_locale, ULOC_FULLNAME_CAPACITY,
    186                           &error);
    187 
    188     // Remove extensions from maximized locale.
    189     // de_Latn_DE@collation=phonebook -> de_Latn_DE
    190     char icu_base_max_locale[ULOC_FULLNAME_CAPACITY];
    191     uloc_getBaseName(icu_max_locale, icu_base_max_locale,
    192                      ULOC_FULLNAME_CAPACITY, &error);
    193 
    194     // Get original name without extensions.
    195     // de_DE@collation=phonebook -> de_DE
    196     char icu_base_locale[ULOC_FULLNAME_CAPACITY];
    197     uloc_getBaseName(icu_locale, icu_base_locale, ULOC_FULLNAME_CAPACITY,
    198                      &error);
    199 
    200     // Convert from ICU locale format to BCP47 format.
    201     // de_Latn_DE -> de-Latn-DE
    202     char base_max_locale[ULOC_FULLNAME_CAPACITY];
    203     uloc_toLanguageTag(icu_base_max_locale, base_max_locale,
    204                        ULOC_FULLNAME_CAPACITY, FALSE, &error);
    205 
    206     // de_DE -> de-DE
    207     char base_locale[ULOC_FULLNAME_CAPACITY];
    208     uloc_toLanguageTag(icu_base_locale, base_locale, ULOC_FULLNAME_CAPACITY,
    209                        FALSE, &error);
    210 
    211     if (U_FAILURE(error)) {
    212       return isolate->Throw(*factory->illegal_argument_string());
    213     }
    214 
    215     Handle<JSObject> result = factory->NewJSObject(isolate->object_function());
    216     Handle<String> value = factory->NewStringFromAsciiChecked(base_max_locale);
    217     JSObject::AddProperty(result, maximized, value, NONE);
    218     value = factory->NewStringFromAsciiChecked(base_locale);
    219     JSObject::AddProperty(result, base, value, NONE);
    220     output->set(i, *result);
    221   }
    222 
    223   Handle<JSArray> result = factory->NewJSArrayWithElements(output);
    224   result->set_length(Smi::FromInt(length));
    225   return *result;
    226 }
    227 
    228 
    229 RUNTIME_FUNCTION(Runtime_IsInitializedIntlObject) {
    230   HandleScope scope(isolate);
    231 
    232   DCHECK(args.length() == 1);
    233 
    234   CONVERT_ARG_HANDLE_CHECKED(Object, input, 0);
    235 
    236   if (!input->IsJSObject()) return isolate->heap()->false_value();
    237   Handle<JSObject> obj = Handle<JSObject>::cast(input);
    238 
    239   Handle<Symbol> marker = isolate->factory()->intl_initialized_marker_symbol();
    240   Handle<Object> tag = JSReceiver::GetDataProperty(obj, marker);
    241   return isolate->heap()->ToBoolean(!tag->IsUndefined());
    242 }
    243 
    244 
    245 RUNTIME_FUNCTION(Runtime_IsInitializedIntlObjectOfType) {
    246   HandleScope scope(isolate);
    247 
    248   DCHECK(args.length() == 2);
    249 
    250   CONVERT_ARG_HANDLE_CHECKED(Object, input, 0);
    251   CONVERT_ARG_HANDLE_CHECKED(String, expected_type, 1);
    252 
    253   if (!input->IsJSObject()) return isolate->heap()->false_value();
    254   Handle<JSObject> obj = Handle<JSObject>::cast(input);
    255 
    256   Handle<Symbol> marker = isolate->factory()->intl_initialized_marker_symbol();
    257   Handle<Object> tag = JSReceiver::GetDataProperty(obj, marker);
    258   return isolate->heap()->ToBoolean(tag->IsString() &&
    259                                     String::cast(*tag)->Equals(*expected_type));
    260 }
    261 
    262 
    263 RUNTIME_FUNCTION(Runtime_MarkAsInitializedIntlObjectOfType) {
    264   HandleScope scope(isolate);
    265 
    266   DCHECK(args.length() == 3);
    267 
    268   CONVERT_ARG_HANDLE_CHECKED(JSObject, input, 0);
    269   CONVERT_ARG_HANDLE_CHECKED(String, type, 1);
    270   CONVERT_ARG_HANDLE_CHECKED(JSObject, impl, 2);
    271 
    272   Handle<Symbol> marker = isolate->factory()->intl_initialized_marker_symbol();
    273   JSObject::SetProperty(input, marker, type, STRICT).Assert();
    274 
    275   marker = isolate->factory()->intl_impl_object_symbol();
    276   JSObject::SetProperty(input, marker, impl, STRICT).Assert();
    277 
    278   return isolate->heap()->undefined_value();
    279 }
    280 
    281 
    282 RUNTIME_FUNCTION(Runtime_GetImplFromInitializedIntlObject) {
    283   HandleScope scope(isolate);
    284 
    285   DCHECK(args.length() == 1);
    286 
    287   CONVERT_ARG_HANDLE_CHECKED(JSObject, input, 0);
    288 
    289   if (!input->IsJSObject()) {
    290     THROW_NEW_ERROR_RETURN_FAILURE(
    291         isolate, NewTypeError(MessageTemplate::kNotIntlObject, input));
    292   }
    293 
    294   Handle<JSObject> obj = Handle<JSObject>::cast(input);
    295 
    296   Handle<Symbol> marker = isolate->factory()->intl_impl_object_symbol();
    297 
    298   Handle<Object> impl = JSReceiver::GetDataProperty(obj, marker);
    299   if (impl->IsTheHole()) {
    300     THROW_NEW_ERROR_RETURN_FAILURE(
    301         isolate, NewTypeError(MessageTemplate::kNotIntlObject, obj));
    302   }
    303   return *impl;
    304 }
    305 
    306 
    307 RUNTIME_FUNCTION(Runtime_CreateDateTimeFormat) {
    308   HandleScope scope(isolate);
    309 
    310   DCHECK(args.length() == 3);
    311 
    312   CONVERT_ARG_HANDLE_CHECKED(String, locale, 0);
    313   CONVERT_ARG_HANDLE_CHECKED(JSObject, options, 1);
    314   CONVERT_ARG_HANDLE_CHECKED(JSObject, resolved, 2);
    315 
    316   Handle<ObjectTemplateInfo> date_format_template = I18N::GetTemplate(isolate);
    317 
    318   // Create an empty object wrapper.
    319   Handle<JSObject> local_object;
    320   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
    321       isolate, local_object,
    322       ApiNatives::InstantiateObject(date_format_template));
    323 
    324   // Set date time formatter as internal field of the resulting JS object.
    325   icu::SimpleDateFormat* date_format =
    326       DateFormat::InitializeDateTimeFormat(isolate, locale, options, resolved);
    327 
    328   if (!date_format) return isolate->ThrowIllegalOperation();
    329 
    330   local_object->SetInternalField(0, reinterpret_cast<Smi*>(date_format));
    331 
    332   Factory* factory = isolate->factory();
    333   Handle<String> key = factory->NewStringFromStaticChars("dateFormat");
    334   Handle<String> value = factory->NewStringFromStaticChars("valid");
    335   JSObject::AddProperty(local_object, key, value, NONE);
    336 
    337   // Make object handle weak so we can delete the data format once GC kicks in.
    338   Handle<Object> wrapper = isolate->global_handles()->Create(*local_object);
    339   GlobalHandles::MakeWeak(wrapper.location(),
    340                           reinterpret_cast<void*>(wrapper.location()),
    341                           DateFormat::DeleteDateFormat);
    342   return *local_object;
    343 }
    344 
    345 
    346 RUNTIME_FUNCTION(Runtime_InternalDateFormat) {
    347   HandleScope scope(isolate);
    348 
    349   DCHECK(args.length() == 2);
    350 
    351   CONVERT_ARG_HANDLE_CHECKED(JSObject, date_format_holder, 0);
    352   CONVERT_ARG_HANDLE_CHECKED(JSDate, date, 1);
    353 
    354   Handle<Object> value;
    355   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value, Object::ToNumber(date));
    356 
    357   icu::SimpleDateFormat* date_format =
    358       DateFormat::UnpackDateFormat(isolate, date_format_holder);
    359   if (!date_format) return isolate->ThrowIllegalOperation();
    360 
    361   icu::UnicodeString result;
    362   date_format->format(value->Number(), result);
    363 
    364   Handle<String> result_str;
    365   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
    366       isolate, result_str,
    367       isolate->factory()->NewStringFromTwoByte(Vector<const uint16_t>(
    368           reinterpret_cast<const uint16_t*>(result.getBuffer()),
    369           result.length())));
    370   return *result_str;
    371 }
    372 
    373 
    374 RUNTIME_FUNCTION(Runtime_InternalDateParse) {
    375   HandleScope scope(isolate);
    376 
    377   DCHECK(args.length() == 2);
    378 
    379   CONVERT_ARG_HANDLE_CHECKED(JSObject, date_format_holder, 0);
    380   CONVERT_ARG_HANDLE_CHECKED(String, date_string, 1);
    381 
    382   v8::String::Utf8Value utf8_date(v8::Utils::ToLocal(date_string));
    383   icu::UnicodeString u_date(icu::UnicodeString::fromUTF8(*utf8_date));
    384   icu::SimpleDateFormat* date_format =
    385       DateFormat::UnpackDateFormat(isolate, date_format_holder);
    386   if (!date_format) return isolate->ThrowIllegalOperation();
    387 
    388   UErrorCode status = U_ZERO_ERROR;
    389   UDate date = date_format->parse(u_date, status);
    390   if (U_FAILURE(status)) return isolate->heap()->undefined_value();
    391 
    392   Handle<JSDate> result;
    393   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
    394       isolate, result,
    395       JSDate::New(isolate->date_function(), isolate->date_function(),
    396                   static_cast<double>(date)));
    397   return *result;
    398 }
    399 
    400 
    401 RUNTIME_FUNCTION(Runtime_CreateNumberFormat) {
    402   HandleScope scope(isolate);
    403 
    404   DCHECK(args.length() == 3);
    405 
    406   CONVERT_ARG_HANDLE_CHECKED(String, locale, 0);
    407   CONVERT_ARG_HANDLE_CHECKED(JSObject, options, 1);
    408   CONVERT_ARG_HANDLE_CHECKED(JSObject, resolved, 2);
    409 
    410   Handle<ObjectTemplateInfo> number_format_template =
    411       I18N::GetTemplate(isolate);
    412 
    413   // Create an empty object wrapper.
    414   Handle<JSObject> local_object;
    415   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
    416       isolate, local_object,
    417       ApiNatives::InstantiateObject(number_format_template));
    418 
    419   // Set number formatter as internal field of the resulting JS object.
    420   icu::DecimalFormat* number_format =
    421       NumberFormat::InitializeNumberFormat(isolate, locale, options, resolved);
    422 
    423   if (!number_format) return isolate->ThrowIllegalOperation();
    424 
    425   local_object->SetInternalField(0, reinterpret_cast<Smi*>(number_format));
    426 
    427   Factory* factory = isolate->factory();
    428   Handle<String> key = factory->NewStringFromStaticChars("numberFormat");
    429   Handle<String> value = factory->NewStringFromStaticChars("valid");
    430   JSObject::AddProperty(local_object, key, value, NONE);
    431 
    432   Handle<Object> wrapper = isolate->global_handles()->Create(*local_object);
    433   GlobalHandles::MakeWeak(wrapper.location(),
    434                           reinterpret_cast<void*>(wrapper.location()),
    435                           NumberFormat::DeleteNumberFormat);
    436   return *local_object;
    437 }
    438 
    439 
    440 RUNTIME_FUNCTION(Runtime_InternalNumberFormat) {
    441   HandleScope scope(isolate);
    442 
    443   DCHECK(args.length() == 2);
    444 
    445   CONVERT_ARG_HANDLE_CHECKED(JSObject, number_format_holder, 0);
    446   CONVERT_ARG_HANDLE_CHECKED(Object, number, 1);
    447 
    448   Handle<Object> value;
    449   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value, Object::ToNumber(number));
    450 
    451   icu::DecimalFormat* number_format =
    452       NumberFormat::UnpackNumberFormat(isolate, number_format_holder);
    453   if (!number_format) return isolate->ThrowIllegalOperation();
    454 
    455   icu::UnicodeString result;
    456   number_format->format(value->Number(), result);
    457 
    458   Handle<String> result_str;
    459   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
    460       isolate, result_str,
    461       isolate->factory()->NewStringFromTwoByte(Vector<const uint16_t>(
    462           reinterpret_cast<const uint16_t*>(result.getBuffer()),
    463           result.length())));
    464   return *result_str;
    465 }
    466 
    467 
    468 RUNTIME_FUNCTION(Runtime_InternalNumberParse) {
    469   HandleScope scope(isolate);
    470 
    471   DCHECK(args.length() == 2);
    472 
    473   CONVERT_ARG_HANDLE_CHECKED(JSObject, number_format_holder, 0);
    474   CONVERT_ARG_HANDLE_CHECKED(String, number_string, 1);
    475 
    476   isolate->CountUsage(v8::Isolate::UseCounterFeature::kIntlV8Parse);
    477 
    478   v8::String::Utf8Value utf8_number(v8::Utils::ToLocal(number_string));
    479   icu::UnicodeString u_number(icu::UnicodeString::fromUTF8(*utf8_number));
    480   icu::DecimalFormat* number_format =
    481       NumberFormat::UnpackNumberFormat(isolate, number_format_holder);
    482   if (!number_format) return isolate->ThrowIllegalOperation();
    483 
    484   UErrorCode status = U_ZERO_ERROR;
    485   icu::Formattable result;
    486   // ICU 4.6 doesn't support parseCurrency call. We need to wait for ICU49
    487   // to be part of Chrome.
    488   // TODO(cira): Include currency parsing code using parseCurrency call.
    489   // We need to check if the formatter parses all currencies or only the
    490   // one it was constructed with (it will impact the API - how to return ISO
    491   // code and the value).
    492   number_format->parse(u_number, result, status);
    493   if (U_FAILURE(status)) return isolate->heap()->undefined_value();
    494 
    495   switch (result.getType()) {
    496     case icu::Formattable::kDouble:
    497       return *isolate->factory()->NewNumber(result.getDouble());
    498     case icu::Formattable::kLong:
    499       return *isolate->factory()->NewNumberFromInt(result.getLong());
    500     case icu::Formattable::kInt64:
    501       return *isolate->factory()->NewNumber(
    502           static_cast<double>(result.getInt64()));
    503     default:
    504       return isolate->heap()->undefined_value();
    505   }
    506 }
    507 
    508 
    509 RUNTIME_FUNCTION(Runtime_CreateCollator) {
    510   HandleScope scope(isolate);
    511 
    512   DCHECK(args.length() == 3);
    513 
    514   CONVERT_ARG_HANDLE_CHECKED(String, locale, 0);
    515   CONVERT_ARG_HANDLE_CHECKED(JSObject, options, 1);
    516   CONVERT_ARG_HANDLE_CHECKED(JSObject, resolved, 2);
    517 
    518   Handle<ObjectTemplateInfo> collator_template = I18N::GetTemplate(isolate);
    519 
    520   // Create an empty object wrapper.
    521   Handle<JSObject> local_object;
    522   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
    523       isolate, local_object, ApiNatives::InstantiateObject(collator_template));
    524 
    525   // Set collator as internal field of the resulting JS object.
    526   icu::Collator* collator =
    527       Collator::InitializeCollator(isolate, locale, options, resolved);
    528 
    529   if (!collator) return isolate->ThrowIllegalOperation();
    530 
    531   local_object->SetInternalField(0, reinterpret_cast<Smi*>(collator));
    532 
    533   Factory* factory = isolate->factory();
    534   Handle<String> key = factory->NewStringFromStaticChars("collator");
    535   Handle<String> value = factory->NewStringFromStaticChars("valid");
    536   JSObject::AddProperty(local_object, key, value, NONE);
    537 
    538   Handle<Object> wrapper = isolate->global_handles()->Create(*local_object);
    539   GlobalHandles::MakeWeak(wrapper.location(),
    540                           reinterpret_cast<void*>(wrapper.location()),
    541                           Collator::DeleteCollator);
    542   return *local_object;
    543 }
    544 
    545 
    546 RUNTIME_FUNCTION(Runtime_InternalCompare) {
    547   HandleScope scope(isolate);
    548 
    549   DCHECK(args.length() == 3);
    550 
    551   CONVERT_ARG_HANDLE_CHECKED(JSObject, collator_holder, 0);
    552   CONVERT_ARG_HANDLE_CHECKED(String, string1, 1);
    553   CONVERT_ARG_HANDLE_CHECKED(String, string2, 2);
    554 
    555   icu::Collator* collator = Collator::UnpackCollator(isolate, collator_holder);
    556   if (!collator) return isolate->ThrowIllegalOperation();
    557 
    558   v8::String::Value string_value1(v8::Utils::ToLocal(string1));
    559   v8::String::Value string_value2(v8::Utils::ToLocal(string2));
    560   const UChar* u_string1 = reinterpret_cast<const UChar*>(*string_value1);
    561   const UChar* u_string2 = reinterpret_cast<const UChar*>(*string_value2);
    562   UErrorCode status = U_ZERO_ERROR;
    563   UCollationResult result =
    564       collator->compare(u_string1, string_value1.length(), u_string2,
    565                         string_value2.length(), status);
    566   if (U_FAILURE(status)) return isolate->ThrowIllegalOperation();
    567 
    568   return *isolate->factory()->NewNumberFromInt(result);
    569 }
    570 
    571 
    572 RUNTIME_FUNCTION(Runtime_StringNormalize) {
    573   HandleScope scope(isolate);
    574   static const UNormalizationMode normalizationForms[] = {
    575       UNORM_NFC, UNORM_NFD, UNORM_NFKC, UNORM_NFKD};
    576 
    577   DCHECK(args.length() == 2);
    578 
    579   CONVERT_ARG_HANDLE_CHECKED(String, stringValue, 0);
    580   CONVERT_NUMBER_CHECKED(int, form_id, Int32, args[1]);
    581   RUNTIME_ASSERT(form_id >= 0 &&
    582                  static_cast<size_t>(form_id) < arraysize(normalizationForms));
    583 
    584   v8::String::Value string_value(v8::Utils::ToLocal(stringValue));
    585   const UChar* u_value = reinterpret_cast<const UChar*>(*string_value);
    586 
    587   // TODO(mnita): check Normalizer2 (not available in ICU 46)
    588   UErrorCode status = U_ZERO_ERROR;
    589   icu::UnicodeString result;
    590   icu::Normalizer::normalize(u_value, normalizationForms[form_id], 0, result,
    591                              status);
    592   if (U_FAILURE(status)) {
    593     return isolate->heap()->undefined_value();
    594   }
    595 
    596   Handle<String> result_str;
    597   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
    598       isolate, result_str,
    599       isolate->factory()->NewStringFromTwoByte(Vector<const uint16_t>(
    600           reinterpret_cast<const uint16_t*>(result.getBuffer()),
    601           result.length())));
    602   return *result_str;
    603 }
    604 
    605 
    606 RUNTIME_FUNCTION(Runtime_CreateBreakIterator) {
    607   HandleScope scope(isolate);
    608 
    609   DCHECK(args.length() == 3);
    610 
    611   CONVERT_ARG_HANDLE_CHECKED(String, locale, 0);
    612   CONVERT_ARG_HANDLE_CHECKED(JSObject, options, 1);
    613   CONVERT_ARG_HANDLE_CHECKED(JSObject, resolved, 2);
    614 
    615   Handle<ObjectTemplateInfo> break_iterator_template =
    616       I18N::GetTemplate2(isolate);
    617 
    618   // Create an empty object wrapper.
    619   Handle<JSObject> local_object;
    620   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
    621       isolate, local_object,
    622       ApiNatives::InstantiateObject(break_iterator_template));
    623 
    624   // Set break iterator as internal field of the resulting JS object.
    625   icu::BreakIterator* break_iterator = BreakIterator::InitializeBreakIterator(
    626       isolate, locale, options, resolved);
    627 
    628   if (!break_iterator) return isolate->ThrowIllegalOperation();
    629 
    630   local_object->SetInternalField(0, reinterpret_cast<Smi*>(break_iterator));
    631   // Make sure that the pointer to adopted text is NULL.
    632   local_object->SetInternalField(1, static_cast<Smi*>(nullptr));
    633 
    634   Factory* factory = isolate->factory();
    635   Handle<String> key = factory->NewStringFromStaticChars("breakIterator");
    636   Handle<String> value = factory->NewStringFromStaticChars("valid");
    637   JSObject::AddProperty(local_object, key, value, NONE);
    638 
    639   // Make object handle weak so we can delete the break iterator once GC kicks
    640   // in.
    641   Handle<Object> wrapper = isolate->global_handles()->Create(*local_object);
    642   GlobalHandles::MakeWeak(wrapper.location(),
    643                           reinterpret_cast<void*>(wrapper.location()),
    644                           BreakIterator::DeleteBreakIterator);
    645   return *local_object;
    646 }
    647 
    648 
    649 RUNTIME_FUNCTION(Runtime_BreakIteratorAdoptText) {
    650   HandleScope scope(isolate);
    651 
    652   DCHECK(args.length() == 2);
    653 
    654   CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0);
    655   CONVERT_ARG_HANDLE_CHECKED(String, text, 1);
    656 
    657   icu::BreakIterator* break_iterator =
    658       BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder);
    659   if (!break_iterator) return isolate->ThrowIllegalOperation();
    660 
    661   icu::UnicodeString* u_text = reinterpret_cast<icu::UnicodeString*>(
    662       break_iterator_holder->GetInternalField(1));
    663   delete u_text;
    664 
    665   v8::String::Value text_value(v8::Utils::ToLocal(text));
    666   u_text = new icu::UnicodeString(reinterpret_cast<const UChar*>(*text_value),
    667                                   text_value.length());
    668   break_iterator_holder->SetInternalField(1, reinterpret_cast<Smi*>(u_text));
    669 
    670   break_iterator->setText(*u_text);
    671 
    672   return isolate->heap()->undefined_value();
    673 }
    674 
    675 
    676 RUNTIME_FUNCTION(Runtime_BreakIteratorFirst) {
    677   HandleScope scope(isolate);
    678 
    679   DCHECK(args.length() == 1);
    680 
    681   CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0);
    682 
    683   icu::BreakIterator* break_iterator =
    684       BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder);
    685   if (!break_iterator) return isolate->ThrowIllegalOperation();
    686 
    687   return *isolate->factory()->NewNumberFromInt(break_iterator->first());
    688 }
    689 
    690 
    691 RUNTIME_FUNCTION(Runtime_BreakIteratorNext) {
    692   HandleScope scope(isolate);
    693 
    694   DCHECK(args.length() == 1);
    695 
    696   CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0);
    697 
    698   icu::BreakIterator* break_iterator =
    699       BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder);
    700   if (!break_iterator) return isolate->ThrowIllegalOperation();
    701 
    702   return *isolate->factory()->NewNumberFromInt(break_iterator->next());
    703 }
    704 
    705 
    706 RUNTIME_FUNCTION(Runtime_BreakIteratorCurrent) {
    707   HandleScope scope(isolate);
    708 
    709   DCHECK(args.length() == 1);
    710 
    711   CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0);
    712 
    713   icu::BreakIterator* break_iterator =
    714       BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder);
    715   if (!break_iterator) return isolate->ThrowIllegalOperation();
    716 
    717   return *isolate->factory()->NewNumberFromInt(break_iterator->current());
    718 }
    719 
    720 
    721 RUNTIME_FUNCTION(Runtime_BreakIteratorBreakType) {
    722   HandleScope scope(isolate);
    723 
    724   DCHECK(args.length() == 1);
    725 
    726   CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0);
    727 
    728   icu::BreakIterator* break_iterator =
    729       BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder);
    730   if (!break_iterator) return isolate->ThrowIllegalOperation();
    731 
    732   // TODO(cira): Remove cast once ICU fixes base BreakIterator class.
    733   icu::RuleBasedBreakIterator* rule_based_iterator =
    734       static_cast<icu::RuleBasedBreakIterator*>(break_iterator);
    735   int32_t status = rule_based_iterator->getRuleStatus();
    736   // Keep return values in sync with JavaScript BreakType enum.
    737   if (status >= UBRK_WORD_NONE && status < UBRK_WORD_NONE_LIMIT) {
    738     return *isolate->factory()->NewStringFromStaticChars("none");
    739   } else if (status >= UBRK_WORD_NUMBER && status < UBRK_WORD_NUMBER_LIMIT) {
    740     return *isolate->factory()->number_string();
    741   } else if (status >= UBRK_WORD_LETTER && status < UBRK_WORD_LETTER_LIMIT) {
    742     return *isolate->factory()->NewStringFromStaticChars("letter");
    743   } else if (status >= UBRK_WORD_KANA && status < UBRK_WORD_KANA_LIMIT) {
    744     return *isolate->factory()->NewStringFromStaticChars("kana");
    745   } else if (status >= UBRK_WORD_IDEO && status < UBRK_WORD_IDEO_LIMIT) {
    746     return *isolate->factory()->NewStringFromStaticChars("ideo");
    747   } else {
    748     return *isolate->factory()->NewStringFromStaticChars("unknown");
    749   }
    750 }
    751 }  // namespace internal
    752 }  // namespace v8
    753 
    754 #endif  // V8_I18N_SUPPORT
    755