LCOV - code coverage report
Current view: top level - src/runtime - runtime-intl.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 332 357 93.0 %
Date: 2017-10-20 Functions: 26 54 48.1 %

          Line data    Source code
       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             : #ifndef V8_INTL_SUPPORT
       6             : #error Internationalization is expected to be enabled.
       7             : #endif  // V8_INTL_SUPPORT
       8             : 
       9             : #include "src/runtime/runtime-utils.h"
      10             : 
      11             : #include <cmath>
      12             : #include <memory>
      13             : 
      14             : #include "src/api-natives.h"
      15             : #include "src/api.h"
      16             : #include "src/arguments.h"
      17             : #include "src/factory.h"
      18             : #include "src/intl.h"
      19             : #include "src/isolate-inl.h"
      20             : #include "src/messages.h"
      21             : #include "src/objects/intl-objects.h"
      22             : #include "src/utils.h"
      23             : 
      24             : #include "unicode/brkiter.h"
      25             : #include "unicode/calendar.h"
      26             : #include "unicode/coll.h"
      27             : #include "unicode/curramt.h"
      28             : #include "unicode/datefmt.h"
      29             : #include "unicode/dcfmtsym.h"
      30             : #include "unicode/decimfmt.h"
      31             : #include "unicode/dtfmtsym.h"
      32             : #include "unicode/dtptngen.h"
      33             : #include "unicode/fieldpos.h"
      34             : #include "unicode/fpositer.h"
      35             : #include "unicode/locid.h"
      36             : #include "unicode/numfmt.h"
      37             : #include "unicode/numsys.h"
      38             : #include "unicode/plurrule.h"
      39             : #include "unicode/rbbi.h"
      40             : #include "unicode/smpdtfmt.h"
      41             : #include "unicode/timezone.h"
      42             : #include "unicode/translit.h"
      43             : #include "unicode/uchar.h"
      44             : #include "unicode/ucol.h"
      45             : #include "unicode/ucurr.h"
      46             : #include "unicode/uloc.h"
      47             : #include "unicode/unistr.h"
      48             : #include "unicode/unum.h"
      49             : #include "unicode/uvernum.h"
      50             : #include "unicode/uversion.h"
      51             : 
      52             : #if U_ICU_VERSION_MAJOR_NUM >= 59
      53             : #include "unicode/char16ptr.h"
      54             : #endif
      55             : 
      56             : namespace v8 {
      57             : namespace internal {
      58             : 
      59             : // ECMA 402 6.2.3
      60        1688 : RUNTIME_FUNCTION(Runtime_CanonicalizeLanguageTag) {
      61         844 :   HandleScope scope(isolate);
      62             :   v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
      63             : 
      64         844 :   Factory* factory = isolate->factory();
      65             : 
      66             :   DCHECK_EQ(1, args.length());
      67        1688 :   CONVERT_ARG_HANDLE_CHECKED(String, locale_id_str, 0);
      68             : 
      69             :   v8::String::Utf8Value locale_id(v8_isolate,
      70        2532 :                                   v8::Utils::ToLocal(locale_id_str));
      71             : 
      72             :   // TODO(jshin): uloc_{for,to}TanguageTag can fail even for a structually valid
      73             :   // language tag if it's too long (much longer than 100 chars). Even if we
      74             :   // allocate a longer buffer, ICU will still fail if it's too long. Either
      75             :   // propose to Ecma 402 to put a limit on the locale length or change ICU to
      76             :   // handle long locale names better. See
      77             :   // https://ssl.icu-project.org/trac/ticket/13417 .
      78             : 
      79             :   // Return value which denotes invalid language tag.
      80             :   const char* const kInvalidTag = "invalid-tag";
      81             : 
      82         844 :   UErrorCode error = U_ZERO_ERROR;
      83             :   char icu_result[ULOC_FULLNAME_CAPACITY];
      84         844 :   uloc_forLanguageTag(*locale_id, icu_result, ULOC_FULLNAME_CAPACITY, nullptr,
      85         844 :                       &error);
      86         844 :   if (U_FAILURE(error) || error == U_STRING_NOT_TERMINATED_WARNING) {
      87          36 :     return *factory->NewStringFromAsciiChecked(kInvalidTag);
      88             :   }
      89             : 
      90             :   char result[ULOC_FULLNAME_CAPACITY];
      91             : 
      92             :   // Force strict BCP47 rules.
      93         826 :   uloc_toLanguageTag(icu_result, result, ULOC_FULLNAME_CAPACITY, TRUE, &error);
      94             : 
      95         826 :   if (U_FAILURE(error) || error == U_STRING_NOT_TERMINATED_WARNING) {
      96          18 :     return *factory->NewStringFromAsciiChecked(kInvalidTag);
      97             :   }
      98             : 
      99        2478 :   return *factory->NewStringFromAsciiChecked(result);
     100             : }
     101             : 
     102        1568 : RUNTIME_FUNCTION(Runtime_AvailableLocalesOf) {
     103         784 :   HandleScope scope(isolate);
     104         784 :   Factory* factory = isolate->factory();
     105             : 
     106             :   DCHECK_EQ(1, args.length());
     107        1568 :   CONVERT_ARG_HANDLE_CHECKED(String, service, 0);
     108             : 
     109             :   const icu::Locale* available_locales = nullptr;
     110         784 :   int32_t count = 0;
     111             : 
     112        1568 :   if (service->IsUtf8EqualTo(CStrVector("collator"))) {
     113         195 :     available_locales = icu::Collator::getAvailableLocales(count);
     114        1178 :   } else if (service->IsUtf8EqualTo(CStrVector("numberformat"))) {
     115         213 :     available_locales = icu::NumberFormat::getAvailableLocales(count);
     116         752 :   } else if (service->IsUtf8EqualTo(CStrVector("dateformat"))) {
     117         289 :     available_locales = icu::DateFormat::getAvailableLocales(count);
     118         174 :   } else if (service->IsUtf8EqualTo(CStrVector("breakiterator"))) {
     119          78 :     available_locales = icu::BreakIterator::getAvailableLocales(count);
     120          18 :   } else if (service->IsUtf8EqualTo(CStrVector("pluralrules"))) {
     121             :     // TODO(littledan): For PluralRules, filter out locales that
     122             :     // don't support PluralRules.
     123             :     // PluralRules is missing an appropriate getAvailableLocales method,
     124             :     // so we should filter from all locales, but it's not clear how; see
     125             :     // https://ssl.icu-project.org/trac/ticket/12756
     126           9 :     available_locales = icu::Locale::getAvailableLocales(count);
     127             :   } else {
     128           0 :     UNREACHABLE();
     129             :   }
     130             : 
     131         784 :   UErrorCode error = U_ZERO_ERROR;
     132             :   char result[ULOC_FULLNAME_CAPACITY];
     133         784 :   Handle<JSObject> locales = factory->NewJSObject(isolate->object_function());
     134             : 
     135      110664 :   for (int32_t i = 0; i < count; ++i) {
     136      110664 :     const char* icu_name = available_locales[i].getName();
     137             : 
     138      110664 :     error = U_ZERO_ERROR;
     139             :     // No need to force strict BCP47 rules.
     140      110664 :     uloc_toLanguageTag(icu_name, result, ULOC_FULLNAME_CAPACITY, FALSE, &error);
     141      110664 :     if (U_FAILURE(error) || error == U_STRING_NOT_TERMINATED_WARNING) {
     142             :       // This shouldn't happen, but lets not break the user.
     143             :       continue;
     144             :     }
     145             : 
     146      221328 :     RETURN_FAILURE_ON_EXCEPTION(
     147             :         isolate, JSObject::SetOwnPropertyIgnoreAttributes(
     148             :                      locales, factory->NewStringFromAsciiChecked(result),
     149             :                      factory->NewNumber(i), NONE));
     150             :   }
     151             : 
     152         784 :   return *locales;
     153             : }
     154             : 
     155        1112 : RUNTIME_FUNCTION(Runtime_GetDefaultICULocale) {
     156         556 :   HandleScope scope(isolate);
     157         556 :   Factory* factory = isolate->factory();
     158             : 
     159             :   DCHECK_EQ(0, args.length());
     160             : 
     161        1112 :   icu::Locale default_locale;
     162             : 
     163             :   // Translate ICU's fallback locale to a well-known locale.
     164         556 :   if (strcmp(default_locale.getName(), "en_US_POSIX") == 0) {
     165           0 :     return *factory->NewStringFromStaticChars("en-US");
     166             :   }
     167             : 
     168             :   // Set the locale
     169             :   char result[ULOC_FULLNAME_CAPACITY];
     170         556 :   UErrorCode status = U_ZERO_ERROR;
     171             :   uloc_toLanguageTag(default_locale.getName(), result, ULOC_FULLNAME_CAPACITY,
     172         556 :                      FALSE, &status);
     173         556 :   if (U_SUCCESS(status)) {
     174        1112 :     return *factory->NewStringFromAsciiChecked(result);
     175             :   }
     176             : 
     177         556 :   return *factory->NewStringFromStaticChars("und");
     178             : }
     179             : 
     180           0 : RUNTIME_FUNCTION(Runtime_IsInitializedIntlObject) {
     181           0 :   HandleScope scope(isolate);
     182             : 
     183             :   DCHECK_EQ(1, args.length());
     184             : 
     185           0 :   CONVERT_ARG_HANDLE_CHECKED(Object, input, 0);
     186             : 
     187           0 :   if (!input->IsJSObject()) return isolate->heap()->false_value();
     188           0 :   Handle<JSObject> obj = Handle<JSObject>::cast(input);
     189             : 
     190           0 :   Handle<Symbol> marker = isolate->factory()->intl_initialized_marker_symbol();
     191           0 :   Handle<Object> tag = JSReceiver::GetDataProperty(obj, marker);
     192           0 :   return isolate->heap()->ToBoolean(!tag->IsUndefined(isolate));
     193             : }
     194             : 
     195       24288 : RUNTIME_FUNCTION(Runtime_IsInitializedIntlObjectOfType) {
     196       12144 :   HandleScope scope(isolate);
     197             : 
     198             :   DCHECK_EQ(2, args.length());
     199             : 
     200       12144 :   CONVERT_ARG_HANDLE_CHECKED(Object, input, 0);
     201       24288 :   CONVERT_ARG_HANDLE_CHECKED(String, expected_type, 1);
     202             : 
     203       12144 :   if (!input->IsJSObject()) return isolate->heap()->false_value();
     204       12098 :   Handle<JSObject> obj = Handle<JSObject>::cast(input);
     205             : 
     206       12098 :   Handle<Symbol> marker = isolate->factory()->intl_initialized_marker_symbol();
     207       12098 :   Handle<Object> tag = JSReceiver::GetDataProperty(obj, marker);
     208       23836 :   return isolate->heap()->ToBoolean(tag->IsString() &&
     209       23836 :                                     String::cast(*tag)->Equals(*expected_type));
     210             : }
     211             : 
     212       22572 : RUNTIME_FUNCTION(Runtime_MarkAsInitializedIntlObjectOfType) {
     213       11286 :   HandleScope scope(isolate);
     214             : 
     215             :   DCHECK_EQ(2, args.length());
     216             : 
     217       22572 :   CONVERT_ARG_HANDLE_CHECKED(JSObject, input, 0);
     218       22572 :   CONVERT_ARG_HANDLE_CHECKED(String, type, 1);
     219             : 
     220       11286 :   Handle<Symbol> marker = isolate->factory()->intl_initialized_marker_symbol();
     221       11286 :   JSObject::SetProperty(input, marker, type, LanguageMode::kStrict).Assert();
     222             : 
     223       11286 :   return isolate->heap()->undefined_value();
     224             : }
     225             : 
     226        2541 : RUNTIME_FUNCTION(Runtime_CreateDateTimeFormat) {
     227         847 :   HandleScope scope(isolate);
     228             : 
     229             :   DCHECK_EQ(3, args.length());
     230             : 
     231        1694 :   CONVERT_ARG_HANDLE_CHECKED(String, locale, 0);
     232        1694 :   CONVERT_ARG_HANDLE_CHECKED(JSObject, options, 1);
     233        1694 :   CONVERT_ARG_HANDLE_CHECKED(JSObject, resolved, 2);
     234             : 
     235             :   Handle<JSFunction> constructor(
     236        2541 :       isolate->native_context()->intl_date_time_format_function());
     237             : 
     238             :   Handle<JSObject> local_object;
     239        2541 :   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, local_object,
     240             :                                      JSObject::New(constructor, constructor));
     241             : 
     242             :   // Set date time formatter as embedder field of the resulting JS object.
     243             :   icu::SimpleDateFormat* date_format =
     244         847 :       DateFormat::InitializeDateTimeFormat(isolate, locale, options, resolved);
     245             : 
     246         847 :   if (!date_format) return isolate->ThrowIllegalOperation();
     247             : 
     248         847 :   local_object->SetEmbedderField(0, reinterpret_cast<Smi*>(date_format));
     249             : 
     250             :   // Make object handle weak so we can delete the data format once GC kicks in.
     251         847 :   Handle<Object> wrapper = isolate->global_handles()->Create(*local_object);
     252             :   GlobalHandles::MakeWeak(wrapper.location(), wrapper.location(),
     253             :                           DateFormat::DeleteDateFormat,
     254         847 :                           WeakCallbackType::kInternalFields);
     255         847 :   return *local_object;
     256             : }
     257             : 
     258         890 : RUNTIME_FUNCTION(Runtime_InternalDateFormat) {
     259         445 :   HandleScope scope(isolate);
     260             : 
     261             :   DCHECK_EQ(2, args.length());
     262             : 
     263         890 :   CONVERT_ARG_HANDLE_CHECKED(JSObject, date_format_holder, 0);
     264         890 :   CONVERT_NUMBER_ARG_HANDLE_CHECKED(date, 1);
     265             : 
     266         445 :   double date_value = date->Number();
     267             :   // Check for +-Infinity and Nan
     268         445 :   if (!std::isfinite(date_value)) {
     269         108 :     THROW_NEW_ERROR_RETURN_FAILURE(
     270             :         isolate, NewRangeError(MessageTemplate::kInvalidTimeValue));
     271             :   }
     272             : 
     273             :   icu::SimpleDateFormat* date_format =
     274         391 :       DateFormat::UnpackDateFormat(isolate, date_format_holder);
     275         391 :   CHECK_NOT_NULL(date_format);
     276             : 
     277         782 :   icu::UnicodeString result;
     278         391 :   date_format->format(date_value, result);
     279             : 
     280         782 :   RETURN_RESULT_OR_FAILURE(
     281             :       isolate, isolate->factory()->NewStringFromTwoByte(Vector<const uint16_t>(
     282             :                    reinterpret_cast<const uint16_t*>(result.getBuffer()),
     283         445 :                    result.length())));
     284             : }
     285             : 
     286             : namespace {
     287             : // The list comes from third_party/icu/source/i18n/unicode/udat.h.
     288             : // They're mapped to DateTimeFormat components listed at
     289             : // https://tc39.github.io/ecma402/#sec-datetimeformat-abstracts .
     290             : 
     291         270 : Handle<String> IcuDateFieldIdToDateType(int32_t field_id, Isolate* isolate) {
     292         270 :   switch (field_id) {
     293             :     case -1:
     294             :       return isolate->factory()->literal_string();
     295             :     case UDAT_YEAR_FIELD:
     296             :     case UDAT_EXTENDED_YEAR_FIELD:
     297             :     case UDAT_YEAR_NAME_FIELD:
     298             :       return isolate->factory()->year_string();
     299             :     case UDAT_MONTH_FIELD:
     300             :     case UDAT_STANDALONE_MONTH_FIELD:
     301             :       return isolate->factory()->month_string();
     302             :     case UDAT_DATE_FIELD:
     303             :       return isolate->factory()->day_string();
     304             :     case UDAT_HOUR_OF_DAY1_FIELD:
     305             :     case UDAT_HOUR_OF_DAY0_FIELD:
     306             :     case UDAT_HOUR1_FIELD:
     307             :     case UDAT_HOUR0_FIELD:
     308             :       return isolate->factory()->hour_string();
     309             :     case UDAT_MINUTE_FIELD:
     310             :       return isolate->factory()->minute_string();
     311             :     case UDAT_SECOND_FIELD:
     312             :       return isolate->factory()->second_string();
     313             :     case UDAT_DAY_OF_WEEK_FIELD:
     314             :     case UDAT_DOW_LOCAL_FIELD:
     315             :     case UDAT_STANDALONE_DAY_FIELD:
     316             :       return isolate->factory()->weekday_string();
     317             :     case UDAT_AM_PM_FIELD:
     318             :       return isolate->factory()->dayperiod_string();
     319             :     case UDAT_TIMEZONE_FIELD:
     320             :     case UDAT_TIMEZONE_RFC_FIELD:
     321             :     case UDAT_TIMEZONE_GENERIC_FIELD:
     322             :     case UDAT_TIMEZONE_SPECIAL_FIELD:
     323             :     case UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD:
     324             :     case UDAT_TIMEZONE_ISO_FIELD:
     325             :     case UDAT_TIMEZONE_ISO_LOCAL_FIELD:
     326             :       return isolate->factory()->timeZoneName_string();
     327             :     case UDAT_ERA_FIELD:
     328             :       return isolate->factory()->era_string();
     329             :     default:
     330             :       // Other UDAT_*_FIELD's cannot show up because there is no way to specify
     331             :       // them via options of Intl.DateTimeFormat.
     332           0 :       UNREACHABLE();
     333             :       // To prevent MSVC from issuing C4715 warning.
     334             :       return Handle<String>();
     335             :   }
     336             : }
     337             : 
     338         270 : bool AddElement(Handle<JSArray> array, int index, int32_t field_id,
     339             :                 const icu::UnicodeString& formatted, int32_t begin, int32_t end,
     340             :                 Isolate* isolate) {
     341             :   HandleScope scope(isolate);
     342             :   Factory* factory = isolate->factory();
     343         270 :   Handle<JSObject> element = factory->NewJSObject(isolate->object_function());
     344         270 :   Handle<String> value = IcuDateFieldIdToDateType(field_id, isolate);
     345         270 :   JSObject::AddProperty(element, factory->type_string(), value, NONE);
     346             : 
     347         270 :   icu::UnicodeString field(formatted.tempSubStringBetween(begin, end));
     348         810 :   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
     349             :       isolate, value,
     350             :       factory->NewStringFromTwoByte(Vector<const uint16_t>(
     351             :           reinterpret_cast<const uint16_t*>(field.getBuffer()),
     352             :           field.length())),
     353             :       false);
     354             : 
     355         270 :   JSObject::AddProperty(element, factory->value_string(), value, NONE);
     356         810 :   RETURN_ON_EXCEPTION_VALUE(
     357             :       isolate, JSObject::AddDataElement(array, index, element, NONE), false);
     358         270 :   return true;
     359             : }
     360             : 
     361             : }  // namespace
     362             : 
     363         144 : RUNTIME_FUNCTION(Runtime_InternalDateFormatToParts) {
     364          72 :   HandleScope scope(isolate);
     365          72 :   Factory* factory = isolate->factory();
     366             : 
     367             :   DCHECK_EQ(2, args.length());
     368             : 
     369         144 :   CONVERT_ARG_HANDLE_CHECKED(JSObject, date_format_holder, 0);
     370         144 :   CONVERT_NUMBER_ARG_HANDLE_CHECKED(date, 1);
     371             : 
     372          72 :   double date_value = date->Number();
     373          72 :   if (!std::isfinite(date_value)) {
     374          54 :     THROW_NEW_ERROR_RETURN_FAILURE(
     375             :         isolate, NewRangeError(MessageTemplate::kInvalidTimeValue));
     376             :   }
     377             : 
     378             :   icu::SimpleDateFormat* date_format =
     379          45 :       DateFormat::UnpackDateFormat(isolate, date_format_holder);
     380          45 :   CHECK_NOT_NULL(date_format);
     381             : 
     382          90 :   icu::UnicodeString formatted;
     383          90 :   icu::FieldPositionIterator fp_iter;
     384          90 :   icu::FieldPosition fp;
     385          45 :   UErrorCode status = U_ZERO_ERROR;
     386          45 :   date_format->format(date_value, formatted, &fp_iter, status);
     387          45 :   if (U_FAILURE(status)) return isolate->heap()->undefined_value();
     388             : 
     389          45 :   Handle<JSArray> result = factory->NewJSArray(0);
     390          45 :   int32_t length = formatted.length();
     391          45 :   if (length == 0) return *result;
     392             : 
     393             :   int index = 0;
     394             :   int32_t previous_end_pos = 0;
     395         207 :   while (fp_iter.next(fp)) {
     396         162 :     int32_t begin_pos = fp.getBeginIndex();
     397         162 :     int32_t end_pos = fp.getEndIndex();
     398             : 
     399         162 :     if (previous_end_pos < begin_pos) {
     400         108 :       if (!AddElement(result, index, -1, formatted, previous_end_pos, begin_pos,
     401         108 :                       isolate)) {
     402           0 :         return isolate->heap()->undefined_value();
     403             :       }
     404         108 :       ++index;
     405             :     }
     406         162 :     if (!AddElement(result, index, fp.getField(), formatted, begin_pos, end_pos,
     407         162 :                     isolate)) {
     408           0 :       return isolate->heap()->undefined_value();
     409             :     }
     410             :     previous_end_pos = end_pos;
     411         162 :     ++index;
     412             :   }
     413          45 :   if (previous_end_pos < length) {
     414           0 :     if (!AddElement(result, index, -1, formatted, previous_end_pos, length,
     415           0 :                     isolate)) {
     416           0 :       return isolate->heap()->undefined_value();
     417             :     }
     418             :   }
     419          45 :   JSObject::ValidateElements(*result);
     420          72 :   return *result;
     421             : }
     422             : 
     423        1827 : RUNTIME_FUNCTION(Runtime_CreateNumberFormat) {
     424         609 :   HandleScope scope(isolate);
     425             : 
     426             :   DCHECK_EQ(3, args.length());
     427             : 
     428        1218 :   CONVERT_ARG_HANDLE_CHECKED(String, locale, 0);
     429        1218 :   CONVERT_ARG_HANDLE_CHECKED(JSObject, options, 1);
     430        1218 :   CONVERT_ARG_HANDLE_CHECKED(JSObject, resolved, 2);
     431             : 
     432             :   Handle<JSFunction> constructor(
     433        1827 :       isolate->native_context()->intl_number_format_function());
     434             : 
     435             :   Handle<JSObject> local_object;
     436        1827 :   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, local_object,
     437             :                                      JSObject::New(constructor, constructor));
     438             : 
     439             :   // Set number formatter as embedder field of the resulting JS object.
     440             :   icu::DecimalFormat* number_format =
     441         609 :       NumberFormat::InitializeNumberFormat(isolate, locale, options, resolved);
     442             : 
     443         609 :   if (!number_format) return isolate->ThrowIllegalOperation();
     444             : 
     445         609 :   local_object->SetEmbedderField(0, reinterpret_cast<Smi*>(number_format));
     446             : 
     447         609 :   Handle<Object> wrapper = isolate->global_handles()->Create(*local_object);
     448             :   GlobalHandles::MakeWeak(wrapper.location(), wrapper.location(),
     449             :                           NumberFormat::DeleteNumberFormat,
     450         609 :                           WeakCallbackType::kInternalFields);
     451         609 :   return *local_object;
     452             : }
     453             : 
     454        3946 : RUNTIME_FUNCTION(Runtime_InternalNumberFormat) {
     455        1973 :   HandleScope scope(isolate);
     456             : 
     457             :   DCHECK_EQ(2, args.length());
     458             : 
     459        3946 :   CONVERT_ARG_HANDLE_CHECKED(JSObject, number_format_holder, 0);
     460        1973 :   CONVERT_ARG_HANDLE_CHECKED(Object, number, 1);
     461             : 
     462             :   Handle<Object> value;
     463        3946 :   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value, Object::ToNumber(number));
     464             : 
     465             :   icu::DecimalFormat* number_format =
     466        1973 :       NumberFormat::UnpackNumberFormat(isolate, number_format_holder);
     467        1973 :   CHECK_NOT_NULL(number_format);
     468             : 
     469        3946 :   icu::UnicodeString result;
     470        1973 :   number_format->format(value->Number(), result);
     471             : 
     472        3946 :   RETURN_RESULT_OR_FAILURE(
     473             :       isolate, isolate->factory()->NewStringFromTwoByte(Vector<const uint16_t>(
     474             :                    reinterpret_cast<const uint16_t*>(result.getBuffer()),
     475        1973 :                    result.length())));
     476             : }
     477             : 
     478         234 : RUNTIME_FUNCTION(Runtime_CurrencyDigits) {
     479             :   DCHECK_EQ(1, args.length());
     480             :   v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
     481             : 
     482         234 :   CONVERT_ARG_HANDLE_CHECKED(String, currency, 0);
     483             : 
     484             :   // TODO(littledan): Avoid transcoding the string twice
     485             :   v8::String::Utf8Value currency_string(v8_isolate,
     486         234 :                                         v8::Utils::ToLocal(currency));
     487             :   icu::UnicodeString currency_icu =
     488         234 :       icu::UnicodeString::fromUTF8(*currency_string);
     489             : 
     490             :   DisallowHeapAllocation no_gc;
     491         117 :   UErrorCode status = U_ZERO_ERROR;
     492             : #if U_ICU_VERSION_MAJOR_NUM >= 59
     493             :   uint32_t fraction_digits = ucurr_getDefaultFractionDigits(
     494         117 :       icu::toUCharPtr(currency_icu.getTerminatedBuffer()), &status);
     495             : #else
     496             :   uint32_t fraction_digits = ucurr_getDefaultFractionDigits(
     497             :       currency_icu.getTerminatedBuffer(), &status);
     498             : #endif
     499             :   // For missing currency codes, default to the most common, 2
     500         117 :   if (!U_SUCCESS(status)) fraction_digits = 2;
     501         234 :   return Smi::FromInt(fraction_digits);
     502             : }
     503             : 
     504       29148 : RUNTIME_FUNCTION(Runtime_CreateCollator) {
     505        9716 :   HandleScope scope(isolate);
     506             : 
     507             :   DCHECK_EQ(3, args.length());
     508             : 
     509       19432 :   CONVERT_ARG_HANDLE_CHECKED(String, locale, 0);
     510       19432 :   CONVERT_ARG_HANDLE_CHECKED(JSObject, options, 1);
     511       19432 :   CONVERT_ARG_HANDLE_CHECKED(JSObject, resolved, 2);
     512             : 
     513             :   Handle<JSFunction> constructor(
     514       29148 :       isolate->native_context()->intl_collator_function());
     515             : 
     516             :   Handle<JSObject> local_object;
     517       29148 :   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, local_object,
     518             :                                      JSObject::New(constructor, constructor));
     519             : 
     520             :   // Set collator as embedder field of the resulting JS object.
     521             :   icu::Collator* collator =
     522        9716 :       Collator::InitializeCollator(isolate, locale, options, resolved);
     523             : 
     524        9716 :   if (!collator) return isolate->ThrowIllegalOperation();
     525             : 
     526        9716 :   local_object->SetEmbedderField(0, reinterpret_cast<Smi*>(collator));
     527             : 
     528        9716 :   Handle<Object> wrapper = isolate->global_handles()->Create(*local_object);
     529             :   GlobalHandles::MakeWeak(wrapper.location(), wrapper.location(),
     530             :                           Collator::DeleteCollator,
     531        9716 :                           WeakCallbackType::kInternalFields);
     532        9716 :   return *local_object;
     533             : }
     534             : 
     535      183400 : RUNTIME_FUNCTION(Runtime_InternalCompare) {
     536       91700 :   HandleScope scope(isolate);
     537             : 
     538             :   DCHECK_EQ(3, args.length());
     539             : 
     540      183400 :   CONVERT_ARG_HANDLE_CHECKED(JSObject, collator_holder, 0);
     541      183400 :   CONVERT_ARG_HANDLE_CHECKED(String, string1, 1);
     542      183400 :   CONVERT_ARG_HANDLE_CHECKED(String, string2, 2);
     543             : 
     544       91700 :   icu::Collator* collator = Collator::UnpackCollator(isolate, collator_holder);
     545       91700 :   CHECK_NOT_NULL(collator);
     546             : 
     547       91700 :   string1 = String::Flatten(string1);
     548       91700 :   string2 = String::Flatten(string2);
     549             : 
     550             :   UCollationResult result;
     551       91700 :   UErrorCode status = U_ZERO_ERROR;
     552             :   {
     553             :     DisallowHeapAllocation no_gc;
     554       91700 :     int32_t length1 = string1->length();
     555       91700 :     int32_t length2 = string2->length();
     556       91700 :     String::FlatContent flat1 = string1->GetFlatContent();
     557       91700 :     String::FlatContent flat2 = string2->GetFlatContent();
     558       91700 :     std::unique_ptr<uc16[]> sap1;
     559      183400 :     std::unique_ptr<uc16[]> sap2;
     560             :     icu::UnicodeString string_val1(
     561      183400 :         FALSE, GetUCharBufferFromFlat(flat1, &sap1, length1), length1);
     562             :     icu::UnicodeString string_val2(
     563      183400 :         FALSE, GetUCharBufferFromFlat(flat2, &sap2, length2), length2);
     564      183400 :     result = collator->compare(string_val1, string_val2, status);
     565             :   }
     566       91700 :   if (U_FAILURE(status)) return isolate->ThrowIllegalOperation();
     567             : 
     568      183400 :   return *isolate->factory()->NewNumberFromInt(result);
     569             : }
     570             : 
     571          81 : RUNTIME_FUNCTION(Runtime_CreatePluralRules) {
     572          27 :   HandleScope scope(isolate);
     573             : 
     574             :   DCHECK_EQ(3, args.length());
     575             : 
     576          54 :   CONVERT_ARG_HANDLE_CHECKED(String, locale, 0);
     577          54 :   CONVERT_ARG_HANDLE_CHECKED(JSObject, options, 1);
     578          54 :   CONVERT_ARG_HANDLE_CHECKED(JSObject, resolved, 2);
     579             : 
     580             :   Handle<JSFunction> constructor(
     581          81 :       isolate->native_context()->intl_plural_rules_function());
     582             : 
     583             :   Handle<JSObject> local_object;
     584          81 :   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, local_object,
     585             :                                      JSObject::New(constructor, constructor));
     586             : 
     587             :   // Set pluralRules as internal field of the resulting JS object.
     588             :   icu::PluralRules* plural_rules;
     589             :   icu::DecimalFormat* decimal_format;
     590             :   bool success = PluralRules::InitializePluralRules(
     591          27 :       isolate, locale, options, resolved, &plural_rules, &decimal_format);
     592             : 
     593          27 :   if (!success) return isolate->ThrowIllegalOperation();
     594             : 
     595          54 :   local_object->SetEmbedderField(0, reinterpret_cast<Smi*>(plural_rules));
     596          54 :   local_object->SetEmbedderField(1, reinterpret_cast<Smi*>(decimal_format));
     597             : 
     598          27 :   Handle<Object> wrapper = isolate->global_handles()->Create(*local_object);
     599             :   GlobalHandles::MakeWeak(wrapper.location(), wrapper.location(),
     600             :                           PluralRules::DeletePluralRules,
     601          27 :                           WeakCallbackType::kInternalFields);
     602          27 :   return *local_object;
     603             : }
     604             : 
     605         360 : RUNTIME_FUNCTION(Runtime_PluralRulesSelect) {
     606         180 :   HandleScope scope(isolate);
     607             : 
     608             :   DCHECK_EQ(2, args.length());
     609             : 
     610         360 :   CONVERT_ARG_HANDLE_CHECKED(JSObject, plural_rules_holder, 0);
     611         180 :   CONVERT_ARG_HANDLE_CHECKED(Object, number, 1);
     612             : 
     613             :   icu::PluralRules* plural_rules =
     614         180 :       PluralRules::UnpackPluralRules(isolate, plural_rules_holder);
     615         180 :   CHECK_NOT_NULL(plural_rules);
     616             : 
     617             :   icu::DecimalFormat* number_format =
     618         180 :       PluralRules::UnpackNumberFormat(isolate, plural_rules_holder);
     619         180 :   CHECK_NOT_NULL(number_format);
     620             : 
     621             :   // Currently, PluralRules doesn't implement all the options for rounding that
     622             :   // the Intl spec provides; format and parse the number to round to the
     623             :   // appropriate amount, then apply PluralRules.
     624             :   //
     625             :   // TODO(littledan): If a future ICU version supports an extended API to avoid
     626             :   // this step, then switch to that API. Bug thread:
     627             :   // http://bugs.icu-project.org/trac/ticket/12763
     628         360 :   icu::UnicodeString rounded_string;
     629         180 :   number_format->format(number->Number(), rounded_string);
     630             : 
     631         360 :   icu::Formattable formattable;
     632         180 :   UErrorCode status = U_ZERO_ERROR;
     633         180 :   number_format->parse(rounded_string, formattable, status);
     634         180 :   if (!U_SUCCESS(status)) return isolate->ThrowIllegalOperation();
     635             : 
     636         180 :   double rounded = formattable.getDouble(status);
     637         180 :   if (!U_SUCCESS(status)) return isolate->ThrowIllegalOperation();
     638             : 
     639         360 :   icu::UnicodeString result = plural_rules->select(rounded);
     640             :   return *isolate->factory()
     641             :               ->NewStringFromTwoByte(Vector<const uint16_t>(
     642             :                   reinterpret_cast<const uint16_t*>(
     643         180 :                       icu::toUCharPtr(result.getBuffer())),
     644         540 :                   result.length()))
     645         540 :               .ToHandleChecked();
     646             : }
     647             : 
     648         345 : RUNTIME_FUNCTION(Runtime_CreateBreakIterator) {
     649         115 :   HandleScope scope(isolate);
     650             : 
     651             :   DCHECK_EQ(3, args.length());
     652             : 
     653         230 :   CONVERT_ARG_HANDLE_CHECKED(String, locale, 0);
     654         230 :   CONVERT_ARG_HANDLE_CHECKED(JSObject, options, 1);
     655         230 :   CONVERT_ARG_HANDLE_CHECKED(JSObject, resolved, 2);
     656             : 
     657             :   Handle<JSFunction> constructor(
     658         345 :       isolate->native_context()->intl_v8_break_iterator_function());
     659             : 
     660             :   Handle<JSObject> local_object;
     661         345 :   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, local_object,
     662             :                                      JSObject::New(constructor, constructor));
     663             : 
     664             :   // Set break iterator as embedder field of the resulting JS object.
     665             :   icu::BreakIterator* break_iterator = V8BreakIterator::InitializeBreakIterator(
     666         115 :       isolate, locale, options, resolved);
     667             : 
     668         115 :   if (!break_iterator) return isolate->ThrowIllegalOperation();
     669             : 
     670         115 :   local_object->SetEmbedderField(0, reinterpret_cast<Smi*>(break_iterator));
     671             :   // Make sure that the pointer to adopted text is nullptr.
     672         115 :   local_object->SetEmbedderField(1, static_cast<Smi*>(nullptr));
     673             : 
     674             :   // Make object handle weak so we can delete the break iterator once GC kicks
     675             :   // in.
     676         115 :   Handle<Object> wrapper = isolate->global_handles()->Create(*local_object);
     677             :   GlobalHandles::MakeWeak(wrapper.location(), wrapper.location(),
     678             :                           V8BreakIterator::DeleteBreakIterator,
     679         115 :                           WeakCallbackType::kInternalFields);
     680         115 :   return *local_object;
     681             : }
     682             : 
     683          46 : RUNTIME_FUNCTION(Runtime_BreakIteratorAdoptText) {
     684          23 :   HandleScope scope(isolate);
     685             : 
     686             :   DCHECK_EQ(2, args.length());
     687             : 
     688          46 :   CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0);
     689          46 :   CONVERT_ARG_HANDLE_CHECKED(String, text, 1);
     690             : 
     691             :   icu::BreakIterator* break_iterator =
     692          23 :       V8BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder);
     693          23 :   CHECK_NOT_NULL(break_iterator);
     694             : 
     695             :   icu::UnicodeString* u_text = reinterpret_cast<icu::UnicodeString*>(
     696          23 :       break_iterator_holder->GetEmbedderField(1));
     697          23 :   delete u_text;
     698             : 
     699          23 :   int length = text->length();
     700          23 :   text = String::Flatten(text);
     701             :   DisallowHeapAllocation no_gc;
     702          23 :   String::FlatContent flat = text->GetFlatContent();
     703          46 :   std::unique_ptr<uc16[]> sap;
     704          23 :   const UChar* text_value = GetUCharBufferFromFlat(flat, &sap, length);
     705          23 :   u_text = new icu::UnicodeString(text_value, length);
     706          23 :   break_iterator_holder->SetEmbedderField(1, reinterpret_cast<Smi*>(u_text));
     707             : 
     708          23 :   break_iterator->setText(*u_text);
     709             : 
     710          46 :   return isolate->heap()->undefined_value();
     711             : }
     712             : 
     713          36 : RUNTIME_FUNCTION(Runtime_BreakIteratorFirst) {
     714          18 :   HandleScope scope(isolate);
     715             : 
     716             :   DCHECK_EQ(1, args.length());
     717             : 
     718          36 :   CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0);
     719             : 
     720             :   icu::BreakIterator* break_iterator =
     721          18 :       V8BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder);
     722          18 :   CHECK_NOT_NULL(break_iterator);
     723             : 
     724          36 :   return *isolate->factory()->NewNumberFromInt(break_iterator->first());
     725             : }
     726             : 
     727         614 : RUNTIME_FUNCTION(Runtime_BreakIteratorNext) {
     728         307 :   HandleScope scope(isolate);
     729             : 
     730             :   DCHECK_EQ(1, args.length());
     731             : 
     732         614 :   CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0);
     733             : 
     734             :   icu::BreakIterator* break_iterator =
     735         307 :       V8BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder);
     736         307 :   CHECK_NOT_NULL(break_iterator);
     737             : 
     738         614 :   return *isolate->factory()->NewNumberFromInt(break_iterator->next());
     739             : }
     740             : 
     741           0 : RUNTIME_FUNCTION(Runtime_BreakIteratorCurrent) {
     742           0 :   HandleScope scope(isolate);
     743             : 
     744             :   DCHECK_EQ(1, args.length());
     745             : 
     746           0 :   CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0);
     747             : 
     748             :   icu::BreakIterator* break_iterator =
     749           0 :       V8BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder);
     750           0 :   CHECK_NOT_NULL(break_iterator);
     751             : 
     752           0 :   return *isolate->factory()->NewNumberFromInt(break_iterator->current());
     753             : }
     754             : 
     755         558 : RUNTIME_FUNCTION(Runtime_BreakIteratorBreakType) {
     756         279 :   HandleScope scope(isolate);
     757             : 
     758             :   DCHECK_EQ(1, args.length());
     759             : 
     760         558 :   CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0);
     761             : 
     762             :   icu::BreakIterator* break_iterator =
     763         279 :       V8BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder);
     764         279 :   CHECK_NOT_NULL(break_iterator);
     765             : 
     766             :   // TODO(cira): Remove cast once ICU fixes base BreakIterator class.
     767             :   icu::RuleBasedBreakIterator* rule_based_iterator =
     768             :       static_cast<icu::RuleBasedBreakIterator*>(break_iterator);
     769         279 :   int32_t status = rule_based_iterator->getRuleStatus();
     770             :   // Keep return values in sync with JavaScript BreakType enum.
     771         279 :   if (status >= UBRK_WORD_NONE && status < UBRK_WORD_NONE_LIMIT) {
     772         270 :     return *isolate->factory()->NewStringFromStaticChars("none");
     773         144 :   } else if (status >= UBRK_WORD_NUMBER && status < UBRK_WORD_NUMBER_LIMIT) {
     774           0 :     return isolate->heap()->number_string();
     775         144 :   } else if (status >= UBRK_WORD_LETTER && status < UBRK_WORD_LETTER_LIMIT) {
     776         180 :     return *isolate->factory()->NewStringFromStaticChars("letter");
     777          54 :   } else if (status >= UBRK_WORD_KANA && status < UBRK_WORD_KANA_LIMIT) {
     778           0 :     return *isolate->factory()->NewStringFromStaticChars("kana");
     779          54 :   } else if (status >= UBRK_WORD_IDEO && status < UBRK_WORD_IDEO_LIMIT) {
     780         108 :     return *isolate->factory()->NewStringFromStaticChars("ideo");
     781             :   } else {
     782           0 :     return *isolate->factory()->NewStringFromStaticChars("unknown");
     783         279 :   }
     784             : }
     785             : 
     786        9260 : RUNTIME_FUNCTION(Runtime_StringToLowerCaseIntl) {
     787        4630 :   HandleScope scope(isolate);
     788             :   DCHECK_EQ(args.length(), 1);
     789        9260 :   CONVERT_ARG_HANDLE_CHECKED(String, s, 0);
     790        4630 :   s = String::Flatten(s);
     791        4630 :   return ConvertToLower(s, isolate);
     792             : }
     793             : 
     794        2594 : RUNTIME_FUNCTION(Runtime_StringToUpperCaseIntl) {
     795        1297 :   HandleScope scope(isolate);
     796             :   DCHECK_EQ(args.length(), 1);
     797        2594 :   CONVERT_ARG_HANDLE_CHECKED(String, s, 0);
     798        1297 :   s = String::Flatten(s);
     799        1297 :   return ConvertToUpper(s, isolate);
     800             : }
     801             : 
     802        1530 : RUNTIME_FUNCTION(Runtime_StringLocaleConvertCase) {
     803         765 :   HandleScope scope(isolate);
     804             :   DCHECK_EQ(args.length(), 3);
     805        1530 :   CONVERT_ARG_HANDLE_CHECKED(String, s, 0);
     806        1530 :   CONVERT_BOOLEAN_ARG_CHECKED(is_upper, 1);
     807        1530 :   CONVERT_ARG_HANDLE_CHECKED(String, lang_arg, 2);
     808             : 
     809             :   // Primary language tag can be up to 8 characters long in theory.
     810             :   // https://tools.ietf.org/html/bcp47#section-2.2.1
     811             :   DCHECK_LE(lang_arg->length(), 8);
     812         765 :   lang_arg = String::Flatten(lang_arg);
     813         765 :   s = String::Flatten(s);
     814             : 
     815             :   // All the languages requiring special-handling have two-letter codes.
     816             :   // Note that we have to check for '!= 2' here because private-use language
     817             :   // tags (x-foo) or grandfathered irregular tags (e.g. i-enochian) would have
     818             :   // only 'x' or 'i' when they get here.
     819         765 :   if (V8_UNLIKELY(lang_arg->length() != 2))
     820         135 :     return ConvertCase(s, is_upper, isolate);
     821             : 
     822             :   char c1, c2;
     823             :   {
     824             :     DisallowHeapAllocation no_gc;
     825         630 :     String::FlatContent lang = lang_arg->GetFlatContent();
     826         630 :     c1 = lang.Get(0);
     827         630 :     c2 = lang.Get(1);
     828             :   }
     829             :   // TODO(jshin): Consider adding a fast path for ASCII or Latin-1. The fastpath
     830             :   // in the root locale needs to be adjusted for az, lt and tr because even case
     831             :   // mapping of ASCII range characters are different in those locales.
     832             :   // Greek (el) does not require any adjustment.
     833         630 :   if (V8_UNLIKELY(c1 == 't' && c2 == 'r'))
     834         108 :     return LocaleConvertCase(s, isolate, is_upper, "tr");
     835         522 :   if (V8_UNLIKELY(c1 == 'e' && c2 == 'l'))
     836         225 :     return LocaleConvertCase(s, isolate, is_upper, "el");
     837         297 :   if (V8_UNLIKELY(c1 == 'l' && c2 == 't'))
     838          18 :     return LocaleConvertCase(s, isolate, is_upper, "lt");
     839         279 :   if (V8_UNLIKELY(c1 == 'a' && c2 == 'z'))
     840          36 :     return LocaleConvertCase(s, isolate, is_upper, "az");
     841             : 
     842         243 :   return ConvertCase(s, is_upper, isolate);
     843             : }
     844             : 
     845      366768 : RUNTIME_FUNCTION(Runtime_DateCacheVersion) {
     846       73337 :   HandleScope scope(isolate);
     847             :   DCHECK_EQ(0, args.length());
     848       73337 :   if (isolate->serializer_enabled()) return isolate->heap()->undefined_value();
     849       73337 :   if (!isolate->eternal_handles()->Exists(EternalHandles::DATE_CACHE_VERSION)) {
     850             :     Handle<FixedArray> date_cache_version =
     851          83 :         isolate->factory()->NewFixedArray(1, TENURED);
     852          83 :     date_cache_version->set(0, Smi::kZero);
     853             :     isolate->eternal_handles()->CreateSingleton(
     854          83 :         isolate, *date_cache_version, EternalHandles::DATE_CACHE_VERSION);
     855             :   }
     856             :   Handle<FixedArray> date_cache_version =
     857             :       Handle<FixedArray>::cast(isolate->eternal_handles()->GetSingleton(
     858       73337 :           EternalHandles::DATE_CACHE_VERSION));
     859       73337 :   return date_cache_version->get(0);
     860             : }
     861             : 
     862             : }  // namespace internal
     863             : }  // namespace v8

Generated by: LCOV version 1.10