LCOV - code coverage report
Current view: top level - src/objects - intl-objects.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 281 346 81.2 %
Date: 2017-04-26 Functions: 19 19 100.0 %

          Line data    Source code
       1             : // Copyright 2013 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/objects/intl-objects.h"
      10             : 
      11             : #include <memory>
      12             : 
      13             : #include "src/api.h"
      14             : #include "src/factory.h"
      15             : #include "src/isolate.h"
      16             : #include "src/objects-inl.h"
      17             : #include "src/objects/intl-objects-inl.h"
      18             : 
      19             : #include "unicode/brkiter.h"
      20             : #include "unicode/bytestream.h"
      21             : #include "unicode/calendar.h"
      22             : #include "unicode/coll.h"
      23             : #include "unicode/curramt.h"
      24             : #include "unicode/dcfmtsym.h"
      25             : #include "unicode/decimfmt.h"
      26             : #include "unicode/dtfmtsym.h"
      27             : #include "unicode/dtptngen.h"
      28             : #include "unicode/gregocal.h"
      29             : #include "unicode/locid.h"
      30             : #include "unicode/numfmt.h"
      31             : #include "unicode/numsys.h"
      32             : #include "unicode/rbbi.h"
      33             : #include "unicode/smpdtfmt.h"
      34             : #include "unicode/timezone.h"
      35             : #include "unicode/uchar.h"
      36             : #include "unicode/ucol.h"
      37             : #include "unicode/ucurr.h"
      38             : #include "unicode/unum.h"
      39             : #include "unicode/uvernum.h"
      40             : #include "unicode/uversion.h"
      41             : 
      42             : #if U_ICU_VERSION_MAJOR_NUM >= 59
      43             : #include "unicode/char16ptr.h"
      44             : #endif
      45             : 
      46             : namespace v8 {
      47             : namespace internal {
      48             : 
      49             : namespace {
      50             : 
      51       33564 : bool ExtractStringSetting(Isolate* isolate, Handle<JSObject> options,
      52             :                           const char* key, icu::UnicodeString* setting) {
      53       33564 :   Handle<String> str = isolate->factory()->NewStringFromAsciiChecked(key);
      54             :   Handle<Object> object =
      55       67128 :       JSReceiver::GetProperty(options, str).ToHandleChecked();
      56       33564 :   if (object->IsString()) {
      57             :     v8::String::Utf8Value utf8_string(
      58       18012 :         v8::Utils::ToLocal(Handle<String>::cast(object)));
      59       36024 :     *setting = icu::UnicodeString::fromUTF8(*utf8_string);
      60       18012 :     return true;
      61             :   }
      62             :   return false;
      63             : }
      64             : 
      65        3670 : bool ExtractIntegerSetting(Isolate* isolate, Handle<JSObject> options,
      66             :                            const char* key, int32_t* value) {
      67        3670 :   Handle<String> str = isolate->factory()->NewStringFromAsciiChecked(key);
      68             :   Handle<Object> object =
      69        7340 :       JSReceiver::GetProperty(options, str).ToHandleChecked();
      70        3670 :   if (object->IsNumber()) {
      71        2286 :     object->ToInt32(value);
      72        2286 :     return true;
      73             :   }
      74             :   return false;
      75             : }
      76             : 
      77       30926 : bool ExtractBooleanSetting(Isolate* isolate, Handle<JSObject> options,
      78             :                            const char* key, bool* value) {
      79       30926 :   Handle<String> str = isolate->factory()->NewStringFromAsciiChecked(key);
      80             :   Handle<Object> object =
      81       61852 :       JSReceiver::GetProperty(options, str).ToHandleChecked();
      82       30926 :   if (object->IsBoolean()) {
      83       15830 :     *value = object->BooleanValue();
      84       15830 :     return true;
      85             :   }
      86             :   return false;
      87             : }
      88             : 
      89        1133 : icu::SimpleDateFormat* CreateICUDateFormat(Isolate* isolate,
      90             :                                            const icu::Locale& icu_locale,
      91             :                                            Handle<JSObject> options) {
      92             :   // Create time zone as specified by the user. We have to re-create time zone
      93             :   // since calendar takes ownership.
      94             :   icu::TimeZone* tz = NULL;
      95             :   icu::UnicodeString timezone;
      96        1133 :   if (ExtractStringSetting(isolate, options, "timeZone", &timezone)) {
      97         355 :     tz = icu::TimeZone::createTimeZone(timezone);
      98             :   } else {
      99         778 :     tz = icu::TimeZone::createDefault();
     100             :   }
     101             : 
     102             :   // Create a calendar using locale, and apply time zone to it.
     103        1133 :   UErrorCode status = U_ZERO_ERROR;
     104             :   icu::Calendar* calendar =
     105        1133 :       icu::Calendar::createInstance(tz, icu_locale, status);
     106             : 
     107        2266 :   if (calendar->getDynamicClassID() ==
     108        1133 :       icu::GregorianCalendar::getStaticClassID()) {
     109             :     icu::GregorianCalendar* gc = (icu::GregorianCalendar*)calendar;
     110        1049 :     UErrorCode status = U_ZERO_ERROR;
     111             :     // The beginning of ECMAScript time, namely -(2**53)
     112             :     const double start_of_time = -9007199254740992;
     113        1049 :     gc->setGregorianChange(start_of_time, status);
     114             :     DCHECK(U_SUCCESS(status));
     115             :   }
     116             : 
     117             :   // Make formatter from skeleton. Calendar and numbering system are added
     118             :   // to the locale as Unicode extension (if they were specified at all).
     119             :   icu::SimpleDateFormat* date_format = NULL;
     120        1133 :   icu::UnicodeString skeleton;
     121        1133 :   if (ExtractStringSetting(isolate, options, "skeleton", &skeleton)) {
     122             :     std::unique_ptr<icu::DateTimePatternGenerator> generator(
     123        1133 :         icu::DateTimePatternGenerator::createInstance(icu_locale, status));
     124        1133 :     icu::UnicodeString pattern;
     125        1133 :     if (U_SUCCESS(status))
     126        2266 :       pattern = generator->getBestPattern(skeleton, status);
     127             : 
     128        1133 :     date_format = new icu::SimpleDateFormat(pattern, icu_locale, status);
     129        1133 :     if (U_SUCCESS(status)) {
     130        1133 :       date_format->adoptCalendar(calendar);
     131             :     }
     132             :   }
     133             : 
     134        1133 :   if (U_FAILURE(status)) {
     135           0 :     delete calendar;
     136           0 :     delete date_format;
     137             :     date_format = nullptr;
     138             :   }
     139             : 
     140        1133 :   return date_format;
     141             : }
     142             : 
     143        2266 : void SetResolvedDateSettings(Isolate* isolate, const icu::Locale& icu_locale,
     144             :                              icu::SimpleDateFormat* date_format,
     145             :                              Handle<JSObject> resolved) {
     146             :   Factory* factory = isolate->factory();
     147        1133 :   UErrorCode status = U_ZERO_ERROR;
     148             :   icu::UnicodeString pattern;
     149        1133 :   date_format->toPattern(pattern);
     150             :   JSObject::SetProperty(
     151             :       resolved, factory->intl_pattern_symbol(),
     152             :       factory
     153             :           ->NewStringFromTwoByte(Vector<const uint16_t>(
     154             :               reinterpret_cast<const uint16_t*>(pattern.getBuffer()),
     155             :               pattern.length()))
     156             :           .ToHandleChecked(),
     157             :       SLOPPY)
     158        2266 :       .Assert();
     159             : 
     160             :   // Set time zone and calendar.
     161        1133 :   const icu::Calendar* calendar = date_format->getCalendar();
     162             :   // getType() returns legacy calendar type name instead of LDML/BCP47 calendar
     163             :   // key values. intl.js maps them to BCP47 values for key "ca".
     164             :   // TODO(jshin): Consider doing it here, instead.
     165        1133 :   const char* calendar_name = calendar->getType();
     166             :   JSObject::SetProperty(resolved, factory->NewStringFromStaticChars("calendar"),
     167             :                         factory->NewStringFromAsciiChecked(calendar_name),
     168             :                         SLOPPY)
     169        3399 :       .Assert();
     170             : 
     171        1133 :   const icu::TimeZone& tz = calendar->getTimeZone();
     172        1133 :   icu::UnicodeString time_zone;
     173             :   tz.getID(time_zone);
     174             : 
     175        1133 :   icu::UnicodeString canonical_time_zone;
     176        1133 :   icu::TimeZone::getCanonicalID(time_zone, canonical_time_zone, status);
     177        1133 :   if (U_SUCCESS(status)) {
     178        1133 :     if (canonical_time_zone == UNICODE_STRING_SIMPLE("Etc/GMT")) {
     179             :       JSObject::SetProperty(resolved,
     180             :                             factory->NewStringFromStaticChars("timeZone"),
     181             :                             factory->NewStringFromStaticChars("UTC"), SLOPPY)
     182           0 :           .Assert();
     183             :     } else {
     184             :       JSObject::SetProperty(resolved,
     185             :                             factory->NewStringFromStaticChars("timeZone"),
     186             :                             factory
     187             :                                 ->NewStringFromTwoByte(Vector<const uint16_t>(
     188             :                                     reinterpret_cast<const uint16_t*>(
     189             :                                         canonical_time_zone.getBuffer()),
     190             :                                     canonical_time_zone.length()))
     191             :                                 .ToHandleChecked(),
     192             :                             SLOPPY)
     193        3399 :           .Assert();
     194             :     }
     195             :   }
     196             : 
     197             :   // Ugly hack. ICU doesn't expose numbering system in any way, so we have
     198             :   // to assume that for given locale NumberingSystem constructor produces the
     199             :   // same digits as NumberFormat/Calendar would.
     200        1133 :   status = U_ZERO_ERROR;
     201             :   icu::NumberingSystem* numbering_system =
     202        1133 :       icu::NumberingSystem::createInstance(icu_locale, status);
     203        1133 :   if (U_SUCCESS(status)) {
     204        1133 :     const char* ns = numbering_system->getName();
     205             :     JSObject::SetProperty(resolved,
     206             :                           factory->NewStringFromStaticChars("numberingSystem"),
     207             :                           factory->NewStringFromAsciiChecked(ns), SLOPPY)
     208        3399 :         .Assert();
     209             :   } else {
     210             :     JSObject::SetProperty(resolved,
     211             :                           factory->NewStringFromStaticChars("numberingSystem"),
     212             :                           factory->undefined_value(), SLOPPY)
     213           0 :         .Assert();
     214             :   }
     215        1133 :   delete numbering_system;
     216             : 
     217             :   // Set the locale
     218             :   char result[ULOC_FULLNAME_CAPACITY];
     219        1133 :   status = U_ZERO_ERROR;
     220             :   uloc_toLanguageTag(icu_locale.getName(), result, ULOC_FULLNAME_CAPACITY,
     221        1133 :                      FALSE, &status);
     222        1133 :   if (U_SUCCESS(status)) {
     223             :     JSObject::SetProperty(resolved, factory->NewStringFromStaticChars("locale"),
     224             :                           factory->NewStringFromAsciiChecked(result), SLOPPY)
     225        3399 :         .Assert();
     226             :   } else {
     227             :     // This would never happen, since we got the locale from ICU.
     228             :     JSObject::SetProperty(resolved, factory->NewStringFromStaticChars("locale"),
     229             :                           factory->NewStringFromStaticChars("und"), SLOPPY)
     230           0 :         .Assert();
     231        1133 :   }
     232        1133 : }
     233             : 
     234         734 : icu::DecimalFormat* CreateICUNumberFormat(Isolate* isolate,
     235             :                                           const icu::Locale& icu_locale,
     236             :                                           Handle<JSObject> options) {
     237             :   // Make formatter from options. Numbering system is added
     238             :   // to the locale as Unicode extension (if it was specified at all).
     239         734 :   UErrorCode status = U_ZERO_ERROR;
     240             :   icu::DecimalFormat* number_format = NULL;
     241             :   icu::UnicodeString style;
     242         734 :   icu::UnicodeString currency;
     243         734 :   if (ExtractStringSetting(isolate, options, "style", &style)) {
     244         734 :     if (style == UNICODE_STRING_SIMPLE("currency")) {
     245             :       icu::UnicodeString display;
     246          98 :       ExtractStringSetting(isolate, options, "currency", &currency);
     247          98 :       ExtractStringSetting(isolate, options, "currencyDisplay", &display);
     248             : 
     249             : #if (U_ICU_VERSION_MAJOR_NUM == 4) && (U_ICU_VERSION_MINOR_NUM <= 6)
     250             :       icu::NumberFormat::EStyles format_style;
     251             :       if (display == UNICODE_STRING_SIMPLE("code")) {
     252             :         format_style = icu::NumberFormat::kIsoCurrencyStyle;
     253             :       } else if (display == UNICODE_STRING_SIMPLE("name")) {
     254             :         format_style = icu::NumberFormat::kPluralCurrencyStyle;
     255             :       } else {
     256             :         format_style = icu::NumberFormat::kCurrencyStyle;
     257             :       }
     258             : #else  // ICU version is 4.8 or above (we ignore versions below 4.0).
     259             :       UNumberFormatStyle format_style;
     260          98 :       if (display == UNICODE_STRING_SIMPLE("code")) {
     261             :         format_style = UNUM_CURRENCY_ISO;
     262          84 :       } else if (display == UNICODE_STRING_SIMPLE("name")) {
     263             :         format_style = UNUM_CURRENCY_PLURAL;
     264             :       } else {
     265             :         format_style = UNUM_CURRENCY;
     266             :       }
     267             : #endif
     268             : 
     269             :       number_format = static_cast<icu::DecimalFormat*>(
     270          98 :           icu::NumberFormat::createInstance(icu_locale, format_style, status));
     271             : 
     272          98 :       if (U_FAILURE(status)) {
     273           0 :         delete number_format;
     274           0 :         return NULL;
     275          98 :       }
     276         636 :     } else if (style == UNICODE_STRING_SIMPLE("percent")) {
     277             :       number_format = static_cast<icu::DecimalFormat*>(
     278          28 :           icu::NumberFormat::createPercentInstance(icu_locale, status));
     279          28 :       if (U_FAILURE(status)) {
     280           0 :         delete number_format;
     281             :         return NULL;
     282             :       }
     283             :       // Make sure 1.1% doesn't go into 2%.
     284          28 :       number_format->setMinimumFractionDigits(1);
     285             :     } else {
     286             :       // Make a decimal instance by default.
     287             :       number_format = static_cast<icu::DecimalFormat*>(
     288         608 :           icu::NumberFormat::createInstance(icu_locale, status));
     289             :     }
     290             :   }
     291             : 
     292         734 :   if (U_FAILURE(status)) {
     293           0 :     delete number_format;
     294             :     return NULL;
     295             :   }
     296             : 
     297             :   // Set all options.
     298        1468 :   if (!currency.isEmpty()) {
     299         196 :     number_format->setCurrency(currency.getBuffer(), status);
     300             :   }
     301             : 
     302             :   int32_t digits;
     303         734 :   if (ExtractIntegerSetting(isolate, options, "minimumIntegerDigits",
     304             :                             &digits)) {
     305         734 :     number_format->setMinimumIntegerDigits(digits);
     306             :   }
     307             : 
     308         734 :   if (ExtractIntegerSetting(isolate, options, "minimumFractionDigits",
     309             :                             &digits)) {
     310         734 :     number_format->setMinimumFractionDigits(digits);
     311             :   }
     312             : 
     313         734 :   if (ExtractIntegerSetting(isolate, options, "maximumFractionDigits",
     314             :                             &digits)) {
     315         734 :     number_format->setMaximumFractionDigits(digits);
     316             :   }
     317             : 
     318             :   bool significant_digits_used = false;
     319         734 :   if (ExtractIntegerSetting(isolate, options, "minimumSignificantDigits",
     320             :                             &digits)) {
     321          42 :     number_format->setMinimumSignificantDigits(digits);
     322             :     significant_digits_used = true;
     323             :   }
     324             : 
     325         734 :   if (ExtractIntegerSetting(isolate, options, "maximumSignificantDigits",
     326             :                             &digits)) {
     327          42 :     number_format->setMaximumSignificantDigits(digits);
     328             :     significant_digits_used = true;
     329             :   }
     330             : 
     331         734 :   number_format->setSignificantDigitsUsed(significant_digits_used);
     332             : 
     333             :   bool grouping;
     334         734 :   if (ExtractBooleanSetting(isolate, options, "useGrouping", &grouping)) {
     335         734 :     number_format->setGroupingUsed(grouping);
     336             :   }
     337             : 
     338             :   // Set rounding mode.
     339         734 :   number_format->setRoundingMode(icu::DecimalFormat::kRoundHalfUp);
     340             : 
     341        1468 :   return number_format;
     342             : }
     343             : 
     344        1468 : void SetResolvedNumberSettings(Isolate* isolate, const icu::Locale& icu_locale,
     345             :                                icu::DecimalFormat* number_format,
     346             :                                Handle<JSObject> resolved) {
     347             :   Factory* factory = isolate->factory();
     348             :   icu::UnicodeString pattern;
     349         734 :   number_format->toPattern(pattern);
     350             :   JSObject::SetProperty(
     351             :       resolved, factory->intl_pattern_symbol(),
     352             :       factory
     353             :           ->NewStringFromTwoByte(Vector<const uint16_t>(
     354             :               reinterpret_cast<const uint16_t*>(pattern.getBuffer()),
     355             :               pattern.length()))
     356             :           .ToHandleChecked(),
     357             :       SLOPPY)
     358        1468 :       .Assert();
     359             : 
     360             :   // Set resolved currency code in options.currency if not empty.
     361        1468 :   icu::UnicodeString currency(number_format->getCurrency());
     362        1468 :   if (!currency.isEmpty()) {
     363             :     JSObject::SetProperty(
     364             :         resolved, factory->NewStringFromStaticChars("currency"),
     365             :         factory
     366             :             ->NewStringFromTwoByte(Vector<const uint16_t>(
     367             :                 reinterpret_cast<const uint16_t*>(currency.getBuffer()),
     368             :                 currency.length()))
     369             :             .ToHandleChecked(),
     370             :         SLOPPY)
     371         294 :         .Assert();
     372             :   }
     373             : 
     374             :   // Ugly hack. ICU doesn't expose numbering system in any way, so we have
     375             :   // to assume that for given locale NumberingSystem constructor produces the
     376             :   // same digits as NumberFormat/Calendar would.
     377         734 :   UErrorCode status = U_ZERO_ERROR;
     378             :   icu::NumberingSystem* numbering_system =
     379         734 :       icu::NumberingSystem::createInstance(icu_locale, status);
     380         734 :   if (U_SUCCESS(status)) {
     381         734 :     const char* ns = numbering_system->getName();
     382             :     JSObject::SetProperty(resolved,
     383             :                           factory->NewStringFromStaticChars("numberingSystem"),
     384             :                           factory->NewStringFromAsciiChecked(ns), SLOPPY)
     385        2202 :         .Assert();
     386             :   } else {
     387             :     JSObject::SetProperty(resolved,
     388             :                           factory->NewStringFromStaticChars("numberingSystem"),
     389             :                           factory->undefined_value(), SLOPPY)
     390           0 :         .Assert();
     391             :   }
     392         734 :   delete numbering_system;
     393             : 
     394             :   JSObject::SetProperty(
     395             :       resolved, factory->NewStringFromStaticChars("useGrouping"),
     396         734 :       factory->ToBoolean(number_format->isGroupingUsed()), SLOPPY)
     397        1468 :       .Assert();
     398             : 
     399             :   JSObject::SetProperty(
     400             :       resolved, factory->NewStringFromStaticChars("minimumIntegerDigits"),
     401             :       factory->NewNumberFromInt(number_format->getMinimumIntegerDigits()),
     402             :       SLOPPY)
     403        1468 :       .Assert();
     404             : 
     405             :   JSObject::SetProperty(
     406             :       resolved, factory->NewStringFromStaticChars("minimumFractionDigits"),
     407             :       factory->NewNumberFromInt(number_format->getMinimumFractionDigits()),
     408             :       SLOPPY)
     409        1468 :       .Assert();
     410             : 
     411             :   JSObject::SetProperty(
     412             :       resolved, factory->NewStringFromStaticChars("maximumFractionDigits"),
     413             :       factory->NewNumberFromInt(number_format->getMaximumFractionDigits()),
     414             :       SLOPPY)
     415        1468 :       .Assert();
     416             : 
     417             :   Handle<String> key =
     418         734 :       factory->NewStringFromStaticChars("minimumSignificantDigits");
     419         734 :   Maybe<bool> maybe = JSReceiver::HasOwnProperty(resolved, key);
     420         734 :   CHECK(maybe.IsJust());
     421         734 :   if (maybe.FromJust()) {
     422             :     JSObject::SetProperty(
     423             :         resolved, factory->NewStringFromStaticChars("minimumSignificantDigits"),
     424             :         factory->NewNumberFromInt(number_format->getMinimumSignificantDigits()),
     425             :         SLOPPY)
     426          84 :         .Assert();
     427             :   }
     428             : 
     429         734 :   key = factory->NewStringFromStaticChars("maximumSignificantDigits");
     430         734 :   maybe = JSReceiver::HasOwnProperty(resolved, key);
     431         734 :   CHECK(maybe.IsJust());
     432         734 :   if (maybe.FromJust()) {
     433             :     JSObject::SetProperty(
     434             :         resolved, factory->NewStringFromStaticChars("maximumSignificantDigits"),
     435             :         factory->NewNumberFromInt(number_format->getMaximumSignificantDigits()),
     436             :         SLOPPY)
     437          84 :         .Assert();
     438             :   }
     439             : 
     440             :   // Set the locale
     441             :   char result[ULOC_FULLNAME_CAPACITY];
     442         734 :   status = U_ZERO_ERROR;
     443             :   uloc_toLanguageTag(icu_locale.getName(), result, ULOC_FULLNAME_CAPACITY,
     444         734 :                      FALSE, &status);
     445         734 :   if (U_SUCCESS(status)) {
     446             :     JSObject::SetProperty(resolved, factory->NewStringFromStaticChars("locale"),
     447             :                           factory->NewStringFromAsciiChecked(result), SLOPPY)
     448        2202 :         .Assert();
     449             :   } else {
     450             :     // This would never happen, since we got the locale from ICU.
     451             :     JSObject::SetProperty(resolved, factory->NewStringFromStaticChars("locale"),
     452             :                           factory->NewStringFromStaticChars("und"), SLOPPY)
     453           0 :         .Assert();
     454         734 :   }
     455         734 : }
     456             : 
     457       15096 : icu::Collator* CreateICUCollator(Isolate* isolate,
     458             :                                  const icu::Locale& icu_locale,
     459             :                                  Handle<JSObject> options) {
     460             :   // Make collator from options.
     461             :   icu::Collator* collator = NULL;
     462       15096 :   UErrorCode status = U_ZERO_ERROR;
     463       15096 :   collator = icu::Collator::createInstance(icu_locale, status);
     464             : 
     465       15096 :   if (U_FAILURE(status)) {
     466           0 :     delete collator;
     467             :     return NULL;
     468             :   }
     469             : 
     470             :   // Set flags first, and then override them with sensitivity if necessary.
     471             :   bool numeric;
     472       15096 :   if (ExtractBooleanSetting(isolate, options, "numeric", &numeric)) {
     473             :     collator->setAttribute(UCOL_NUMERIC_COLLATION, numeric ? UCOL_ON : UCOL_OFF,
     474           0 :                            status);
     475             :   }
     476             : 
     477             :   // Normalization is always on, by the spec. We are free to optimize
     478             :   // if the strings are already normalized (but we don't have a way to tell
     479             :   // that right now).
     480       15096 :   collator->setAttribute(UCOL_NORMALIZATION_MODE, UCOL_ON, status);
     481             : 
     482             :   icu::UnicodeString case_first;
     483       15096 :   if (ExtractStringSetting(isolate, options, "caseFirst", &case_first)) {
     484         336 :     if (case_first == UNICODE_STRING_SIMPLE("upper")) {
     485         336 :       collator->setAttribute(UCOL_CASE_FIRST, UCOL_UPPER_FIRST, status);
     486           0 :     } else if (case_first == UNICODE_STRING_SIMPLE("lower")) {
     487           0 :       collator->setAttribute(UCOL_CASE_FIRST, UCOL_LOWER_FIRST, status);
     488             :     } else {
     489             :       // Default (false/off).
     490           0 :       collator->setAttribute(UCOL_CASE_FIRST, UCOL_OFF, status);
     491             :     }
     492             :   }
     493             : 
     494       15096 :   icu::UnicodeString sensitivity;
     495       15096 :   if (ExtractStringSetting(isolate, options, "sensitivity", &sensitivity)) {
     496       15082 :     if (sensitivity == UNICODE_STRING_SIMPLE("base")) {
     497           0 :       collator->setStrength(icu::Collator::PRIMARY);
     498       15082 :     } else if (sensitivity == UNICODE_STRING_SIMPLE("accent")) {
     499           0 :       collator->setStrength(icu::Collator::SECONDARY);
     500       15082 :     } else if (sensitivity == UNICODE_STRING_SIMPLE("case")) {
     501           0 :       collator->setStrength(icu::Collator::PRIMARY);
     502           0 :       collator->setAttribute(UCOL_CASE_LEVEL, UCOL_ON, status);
     503             :     } else {
     504             :       // variant (default)
     505       15082 :       collator->setStrength(icu::Collator::TERTIARY);
     506             :     }
     507             :   }
     508             : 
     509             :   bool ignore;
     510       15096 :   if (ExtractBooleanSetting(isolate, options, "ignorePunctuation", &ignore)) {
     511       15096 :     if (ignore) {
     512           0 :       collator->setAttribute(UCOL_ALTERNATE_HANDLING, UCOL_SHIFTED, status);
     513             :     }
     514             :   }
     515             : 
     516       15096 :   return collator;
     517             : }
     518             : 
     519       15096 : void SetResolvedCollatorSettings(Isolate* isolate,
     520       15096 :                                  const icu::Locale& icu_locale,
     521             :                                  icu::Collator* collator,
     522             :                                  Handle<JSObject> resolved) {
     523             :   Factory* factory = isolate->factory();
     524       15096 :   UErrorCode status = U_ZERO_ERROR;
     525             : 
     526             :   JSObject::SetProperty(
     527             :       resolved, factory->NewStringFromStaticChars("numeric"),
     528             :       factory->ToBoolean(
     529       15096 :           collator->getAttribute(UCOL_NUMERIC_COLLATION, status) == UCOL_ON),
     530             :       SLOPPY)
     531       30192 :       .Assert();
     532             : 
     533       15096 :   switch (collator->getAttribute(UCOL_CASE_FIRST, status)) {
     534             :     case UCOL_LOWER_FIRST:
     535             :       JSObject::SetProperty(resolved,
     536             :                             factory->NewStringFromStaticChars("caseFirst"),
     537             :                             factory->NewStringFromStaticChars("lower"), SLOPPY)
     538           0 :           .Assert();
     539           0 :       break;
     540             :     case UCOL_UPPER_FIRST:
     541             :       JSObject::SetProperty(resolved,
     542             :                             factory->NewStringFromStaticChars("caseFirst"),
     543             :                             factory->NewStringFromStaticChars("upper"), SLOPPY)
     544        1008 :           .Assert();
     545         336 :       break;
     546             :     default:
     547             :       JSObject::SetProperty(resolved,
     548             :                             factory->NewStringFromStaticChars("caseFirst"),
     549             :                             factory->NewStringFromStaticChars("false"), SLOPPY)
     550       44280 :           .Assert();
     551             :   }
     552             : 
     553       15096 :   switch (collator->getAttribute(UCOL_STRENGTH, status)) {
     554             :     case UCOL_PRIMARY: {
     555             :       JSObject::SetProperty(
     556             :           resolved, factory->NewStringFromStaticChars("strength"),
     557             :           factory->NewStringFromStaticChars("primary"), SLOPPY)
     558           0 :           .Assert();
     559             : 
     560             :       // case level: true + s1 -> case, s1 -> base.
     561           0 :       if (UCOL_ON == collator->getAttribute(UCOL_CASE_LEVEL, status)) {
     562             :         JSObject::SetProperty(resolved,
     563             :                               factory->NewStringFromStaticChars("sensitivity"),
     564             :                               factory->NewStringFromStaticChars("case"), SLOPPY)
     565           0 :             .Assert();
     566             :       } else {
     567             :         JSObject::SetProperty(resolved,
     568             :                               factory->NewStringFromStaticChars("sensitivity"),
     569             :                               factory->NewStringFromStaticChars("base"), SLOPPY)
     570           0 :             .Assert();
     571             :       }
     572             :       break;
     573             :     }
     574             :     case UCOL_SECONDARY:
     575             :       JSObject::SetProperty(
     576             :           resolved, factory->NewStringFromStaticChars("strength"),
     577             :           factory->NewStringFromStaticChars("secondary"), SLOPPY)
     578           0 :           .Assert();
     579             :       JSObject::SetProperty(resolved,
     580             :                             factory->NewStringFromStaticChars("sensitivity"),
     581             :                             factory->NewStringFromStaticChars("accent"), SLOPPY)
     582           0 :           .Assert();
     583           0 :       break;
     584             :     case UCOL_TERTIARY:
     585             :       JSObject::SetProperty(
     586             :           resolved, factory->NewStringFromStaticChars("strength"),
     587             :           factory->NewStringFromStaticChars("tertiary"), SLOPPY)
     588       45288 :           .Assert();
     589             :       JSObject::SetProperty(
     590             :           resolved, factory->NewStringFromStaticChars("sensitivity"),
     591             :           factory->NewStringFromStaticChars("variant"), SLOPPY)
     592       45288 :           .Assert();
     593       15096 :       break;
     594             :     case UCOL_QUATERNARY:
     595             :       // We shouldn't get quaternary and identical from ICU, but if we do
     596             :       // put them into variant.
     597             :       JSObject::SetProperty(
     598             :           resolved, factory->NewStringFromStaticChars("strength"),
     599             :           factory->NewStringFromStaticChars("quaternary"), SLOPPY)
     600           0 :           .Assert();
     601             :       JSObject::SetProperty(
     602             :           resolved, factory->NewStringFromStaticChars("sensitivity"),
     603             :           factory->NewStringFromStaticChars("variant"), SLOPPY)
     604           0 :           .Assert();
     605           0 :       break;
     606             :     default:
     607             :       JSObject::SetProperty(
     608             :           resolved, factory->NewStringFromStaticChars("strength"),
     609             :           factory->NewStringFromStaticChars("identical"), SLOPPY)
     610           0 :           .Assert();
     611             :       JSObject::SetProperty(
     612             :           resolved, factory->NewStringFromStaticChars("sensitivity"),
     613             :           factory->NewStringFromStaticChars("variant"), SLOPPY)
     614           0 :           .Assert();
     615             :   }
     616             : 
     617             :   JSObject::SetProperty(
     618             :       resolved, factory->NewStringFromStaticChars("ignorePunctuation"),
     619             :       factory->ToBoolean(collator->getAttribute(UCOL_ALTERNATE_HANDLING,
     620       15096 :                                                 status) == UCOL_SHIFTED),
     621             :       SLOPPY)
     622       30192 :       .Assert();
     623             : 
     624             :   // Set the locale
     625             :   char result[ULOC_FULLNAME_CAPACITY];
     626       15096 :   status = U_ZERO_ERROR;
     627             :   uloc_toLanguageTag(icu_locale.getName(), result, ULOC_FULLNAME_CAPACITY,
     628       15096 :                      FALSE, &status);
     629       15096 :   if (U_SUCCESS(status)) {
     630             :     JSObject::SetProperty(resolved, factory->NewStringFromStaticChars("locale"),
     631             :                           factory->NewStringFromAsciiChecked(result), SLOPPY)
     632       45288 :         .Assert();
     633             :   } else {
     634             :     // This would never happen, since we got the locale from ICU.
     635             :     JSObject::SetProperty(resolved, factory->NewStringFromStaticChars("locale"),
     636             :                           factory->NewStringFromStaticChars("und"), SLOPPY)
     637           0 :         .Assert();
     638             :   }
     639       15096 : }
     640             : 
     641         176 : icu::BreakIterator* CreateICUBreakIterator(Isolate* isolate,
     642             :                                            const icu::Locale& icu_locale,
     643             :                                            Handle<JSObject> options) {
     644         176 :   UErrorCode status = U_ZERO_ERROR;
     645             :   icu::BreakIterator* break_iterator = NULL;
     646             :   icu::UnicodeString type;
     647         176 :   if (!ExtractStringSetting(isolate, options, "type", &type)) return NULL;
     648             : 
     649         176 :   if (type == UNICODE_STRING_SIMPLE("character")) {
     650             :     break_iterator =
     651           0 :         icu::BreakIterator::createCharacterInstance(icu_locale, status);
     652         176 :   } else if (type == UNICODE_STRING_SIMPLE("sentence")) {
     653             :     break_iterator =
     654           0 :         icu::BreakIterator::createSentenceInstance(icu_locale, status);
     655         176 :   } else if (type == UNICODE_STRING_SIMPLE("line")) {
     656           0 :     break_iterator = icu::BreakIterator::createLineInstance(icu_locale, status);
     657             :   } else {
     658             :     // Defualt is word iterator.
     659         176 :     break_iterator = icu::BreakIterator::createWordInstance(icu_locale, status);
     660             :   }
     661             : 
     662         176 :   if (U_FAILURE(status)) {
     663           0 :     delete break_iterator;
     664             :     return NULL;
     665             :   }
     666             : 
     667         176 :   isolate->CountUsage(v8::Isolate::UseCounterFeature::kBreakIterator);
     668             : 
     669         176 :   return break_iterator;
     670             : }
     671             : 
     672         176 : void SetResolvedBreakIteratorSettings(Isolate* isolate,
     673         176 :                                       const icu::Locale& icu_locale,
     674             :                                       icu::BreakIterator* break_iterator,
     675             :                                       Handle<JSObject> resolved) {
     676             :   Factory* factory = isolate->factory();
     677         176 :   UErrorCode status = U_ZERO_ERROR;
     678             : 
     679             :   // Set the locale
     680             :   char result[ULOC_FULLNAME_CAPACITY];
     681             :   status = U_ZERO_ERROR;
     682             :   uloc_toLanguageTag(icu_locale.getName(), result, ULOC_FULLNAME_CAPACITY,
     683         176 :                      FALSE, &status);
     684         176 :   if (U_SUCCESS(status)) {
     685             :     JSObject::SetProperty(resolved, factory->NewStringFromStaticChars("locale"),
     686             :                           factory->NewStringFromAsciiChecked(result), SLOPPY)
     687         528 :         .Assert();
     688             :   } else {
     689             :     // This would never happen, since we got the locale from ICU.
     690             :     JSObject::SetProperty(resolved, factory->NewStringFromStaticChars("locale"),
     691             :                           factory->NewStringFromStaticChars("und"), SLOPPY)
     692           0 :         .Assert();
     693             :   }
     694         176 : }
     695             : }  // namespace
     696             : 
     697             : // static
     698        1133 : MaybeHandle<JSIntlDateTimeFormat> JSIntlDateTimeFormat::New(
     699        1133 :     Isolate* isolate, Handle<String> locale, Handle<JSObject> options,
     700             :     Handle<JSObject> resolved) {
     701             :   // Convert BCP47 into ICU locale format.
     702        1133 :   UErrorCode status = U_ZERO_ERROR;
     703        1133 :   icu::Locale icu_locale;
     704             :   char icu_result[ULOC_FULLNAME_CAPACITY];
     705        1133 :   int icu_length = 0;
     706        2266 :   v8::String::Utf8Value bcp47_locale(v8::Utils::ToLocal(locale));
     707        1133 :   if (bcp47_locale.length() != 0) {
     708        1133 :     uloc_forLanguageTag(*bcp47_locale, icu_result, ULOC_FULLNAME_CAPACITY,
     709        1133 :                         &icu_length, &status);
     710        1133 :     if (U_FAILURE(status) || icu_length == 0) {
     711           0 :       FATAL("Locale lookup bug Intl.DateTimeFormat");
     712             :     }
     713        1133 :     icu_locale = icu::Locale(icu_result);
     714             :   }
     715             : 
     716             :   icu::SimpleDateFormat* date_format =
     717        1133 :       CreateICUDateFormat(isolate, icu_locale, options);
     718        1133 :   if (!date_format) {
     719             :     // Remove extensions and try again.
     720           0 :     icu::Locale no_extension_locale(icu_locale.getBaseName());
     721           0 :     date_format = CreateICUDateFormat(isolate, no_extension_locale, options);
     722             : 
     723           0 :     if (!date_format) {
     724           0 :       FATAL("Failed to create ICU date format, are ICU data files missing?");
     725             :     }
     726             : 
     727             :     // Set resolved settings (pattern, numbering system, calendar).
     728             :     SetResolvedDateSettings(isolate, no_extension_locale, date_format,
     729           0 :                             resolved);
     730             :   } else {
     731        1133 :     SetResolvedDateSettings(isolate, icu_locale, date_format, resolved);
     732             :   }
     733             : 
     734             :   DCHECK_NOT_NULL(date_format);
     735             : 
     736             :   Handle<JSFunction> constructor(
     737        2266 :       isolate->native_context()->intl_date_time_format_function());
     738             : 
     739             :   Handle<Object> dtf_object;
     740        2266 :   ASSIGN_RETURN_ON_EXCEPTION(isolate, dtf_object,
     741             :                              JSObject::New(constructor, constructor),
     742             :                              JSIntlDateTimeFormat);
     743             :   Handle<JSIntlDateTimeFormat> dtf(
     744             :       reinterpret_cast<JSIntlDateTimeFormat*>(*dtf_object));
     745             : 
     746             :   dtf->set_simple_date_format(date_format);
     747             : 
     748             :   // Make object handle weak so we can delete the data format once GC kicks in.
     749             :   Handle<Object> wrapper = isolate->global_handles()->Create(*dtf);
     750             :   GlobalHandles::MakeWeak(wrapper.location(), wrapper.location(),
     751             :                           JSIntlDateTimeFormat::Delete,
     752        1133 :                           WeakCallbackType::kFinalizer);
     753             : 
     754        1133 :   return dtf;
     755             : }
     756             : 
     757          27 : void JSIntlDateTimeFormat::Delete(const v8::WeakCallbackInfo<void>& data) {
     758             :   Object** wrapper = reinterpret_cast<Object**>(data.GetParameter());
     759          27 :   JSIntlDateTimeFormat* dtf = reinterpret_cast<JSIntlDateTimeFormat*>(*wrapper);
     760          27 :   delete dtf->simple_date_format();
     761          27 :   GlobalHandles::Destroy(wrapper);
     762          27 : }
     763             : 
     764         734 : MaybeHandle<JSIntlNumberFormat> JSIntlNumberFormat::New(
     765         734 :     Isolate* isolate, Handle<String> locale, Handle<JSObject> options,
     766             :     Handle<JSObject> resolved) {
     767             :   // Convert BCP47 into ICU locale format.
     768         734 :   UErrorCode status = U_ZERO_ERROR;
     769         734 :   icu::Locale icu_locale;
     770             :   char icu_result[ULOC_FULLNAME_CAPACITY];
     771         734 :   int icu_length = 0;
     772        1468 :   v8::String::Utf8Value bcp47_locale(v8::Utils::ToLocal(locale));
     773         734 :   if (bcp47_locale.length() != 0) {
     774         734 :     uloc_forLanguageTag(*bcp47_locale, icu_result, ULOC_FULLNAME_CAPACITY,
     775         734 :                         &icu_length, &status);
     776         734 :     if (U_FAILURE(status) || icu_length == 0) {
     777           0 :       FATAL("Locale lookup bug Intl.NumberFormat");
     778             :     }
     779         734 :     icu_locale = icu::Locale(icu_result);
     780             :   }
     781             : 
     782             :   icu::DecimalFormat* number_format =
     783         734 :       CreateICUNumberFormat(isolate, icu_locale, options);
     784         734 :   if (!number_format) {
     785             :     // Remove extensions and try again.
     786           0 :     icu::Locale no_extension_locale(icu_locale.getBaseName());
     787             :     number_format =
     788           0 :         CreateICUNumberFormat(isolate, no_extension_locale, options);
     789             : 
     790           0 :     if (!number_format) {
     791           0 :       FATAL("Failed to create ICU number format, are ICU data files missing?");
     792             :     }
     793             : 
     794             :     // Set resolved settings (pattern, numbering system).
     795             :     SetResolvedNumberSettings(isolate, no_extension_locale, number_format,
     796           0 :                               resolved);
     797             :   } else {
     798         734 :     SetResolvedNumberSettings(isolate, icu_locale, number_format, resolved);
     799             :   }
     800             : 
     801             :   DCHECK_NOT_NULL(number_format);
     802             : 
     803             :   Handle<JSFunction> constructor(
     804        1468 :       isolate->native_context()->intl_number_format_function());
     805             : 
     806             :   Handle<Object> nf_object;
     807        1468 :   ASSIGN_RETURN_ON_EXCEPTION(isolate, nf_object,
     808             :                              JSObject::New(constructor, constructor),
     809             :                              JSIntlNumberFormat);
     810             :   Handle<JSIntlNumberFormat> nf(
     811             :       reinterpret_cast<JSIntlNumberFormat*>(*nf_object));
     812             : 
     813             :   nf->set_decimal_format(number_format);
     814             : 
     815             :   // Make object handle weak so we can delete the data format once GC kicks in.
     816             :   Handle<Object> wrapper = isolate->global_handles()->Create(*nf);
     817             :   GlobalHandles::MakeWeak(wrapper.location(), wrapper.location(),
     818             :                           JSIntlNumberFormat::Delete,
     819         734 :                           WeakCallbackType::kFinalizer);
     820             : 
     821         734 :   return nf;
     822             : }
     823             : 
     824           6 : void JSIntlNumberFormat::Delete(const v8::WeakCallbackInfo<void>& data) {
     825             :   Object** wrapper = reinterpret_cast<Object**>(data.GetParameter());
     826           6 :   JSIntlNumberFormat* nf = reinterpret_cast<JSIntlNumberFormat*>(*wrapper);
     827           6 :   delete nf->decimal_format();
     828           6 :   GlobalHandles::Destroy(wrapper);
     829           6 : }
     830             : 
     831       30192 : MaybeHandle<JSIntlCollator> JSIntlCollator::New(Isolate* isolate,
     832             :                                                 Handle<String> locale,
     833             :                                                 Handle<JSObject> options,
     834             :                                                 Handle<JSObject> resolved) {
     835             :   // Convert BCP47 into ICU locale format.
     836       15096 :   UErrorCode status = U_ZERO_ERROR;
     837       15096 :   icu::Locale icu_locale;
     838             :   char icu_result[ULOC_FULLNAME_CAPACITY];
     839       15096 :   int icu_length = 0;
     840       30192 :   v8::String::Utf8Value bcp47_locale(v8::Utils::ToLocal(locale));
     841       15096 :   if (bcp47_locale.length() != 0) {
     842       15096 :     uloc_forLanguageTag(*bcp47_locale, icu_result, ULOC_FULLNAME_CAPACITY,
     843       15096 :                         &icu_length, &status);
     844       15096 :     if (U_FAILURE(status) || icu_length == 0) {
     845           0 :       FATAL("Locale lookup bug Intl.Collator");
     846             :     }
     847       15096 :     icu_locale = icu::Locale(icu_result);
     848             :   }
     849             : 
     850       15096 :   icu::Collator* collator = CreateICUCollator(isolate, icu_locale, options);
     851       15096 :   if (!collator) {
     852             :     // Remove extensions and try again.
     853           0 :     icu::Locale no_extension_locale(icu_locale.getBaseName());
     854           0 :     collator = CreateICUCollator(isolate, no_extension_locale, options);
     855             : 
     856           0 :     if (!collator) {
     857           0 :       FATAL("Failed to create ICU collator, are ICU data files missing?");
     858             :     }
     859             : 
     860             :     // Set resolved settings (pattern, numbering system).
     861             :     SetResolvedCollatorSettings(isolate, no_extension_locale, collator,
     862           0 :                                 resolved);
     863             :   } else {
     864       15096 :     SetResolvedCollatorSettings(isolate, icu_locale, collator, resolved);
     865             :   }
     866             : 
     867             :   DCHECK_NOT_NULL(collator);
     868             : 
     869             :   Handle<JSFunction> constructor(
     870       30192 :       isolate->native_context()->intl_collator_function());
     871             : 
     872             :   Handle<Object> coll_object;
     873       30192 :   ASSIGN_RETURN_ON_EXCEPTION(isolate, coll_object,
     874             :                              JSObject::New(constructor, constructor),
     875             :                              JSIntlCollator);
     876             :   Handle<JSIntlCollator> coll(reinterpret_cast<JSIntlCollator*>(*coll_object));
     877             : 
     878             :   coll->set_collator(collator);
     879             : 
     880             :   // Make object handle weak so we can delete the data format once GC kicks in.
     881             :   Handle<Object> wrapper = isolate->global_handles()->Create(*coll);
     882             :   GlobalHandles::MakeWeak(wrapper.location(), wrapper.location(),
     883       15096 :                           JSIntlCollator::Delete, WeakCallbackType::kFinalizer);
     884             : 
     885       15096 :   return coll;
     886             : }
     887             : 
     888          24 : void JSIntlCollator::Delete(const v8::WeakCallbackInfo<void>& data) {
     889             :   Object** wrapper = reinterpret_cast<Object**>(data.GetParameter());
     890          24 :   JSIntlCollator* coll = reinterpret_cast<JSIntlCollator*>(*wrapper);
     891          24 :   delete coll->collator();
     892          24 :   GlobalHandles::Destroy(wrapper);
     893          24 : }
     894             : 
     895         176 : MaybeHandle<JSIntlV8BreakIterator> JSIntlV8BreakIterator::New(
     896         176 :     Isolate* isolate, Handle<String> locale, Handle<JSObject> options,
     897             :     Handle<JSObject> resolved) {
     898             :   // Convert BCP47 into ICU locale format.
     899         176 :   UErrorCode status = U_ZERO_ERROR;
     900         176 :   icu::Locale icu_locale;
     901             :   char icu_result[ULOC_FULLNAME_CAPACITY];
     902         176 :   int icu_length = 0;
     903         352 :   v8::String::Utf8Value bcp47_locale(v8::Utils::ToLocal(locale));
     904         176 :   if (bcp47_locale.length() != 0) {
     905         176 :     uloc_forLanguageTag(*bcp47_locale, icu_result, ULOC_FULLNAME_CAPACITY,
     906         176 :                         &icu_length, &status);
     907         176 :     if (U_FAILURE(status) || icu_length == 0) {
     908           0 :       FATAL("Locale lookup bug Intl.v8BreakIterator");
     909             :     }
     910         176 :     icu_locale = icu::Locale(icu_result);
     911             :   }
     912             : 
     913             :   icu::BreakIterator* break_iterator =
     914         176 :       CreateICUBreakIterator(isolate, icu_locale, options);
     915         176 :   if (!break_iterator) {
     916             :     // Remove extensions and try again.
     917           0 :     icu::Locale no_extension_locale(icu_locale.getBaseName());
     918             :     break_iterator =
     919           0 :         CreateICUBreakIterator(isolate, no_extension_locale, options);
     920             : 
     921           0 :     if (!break_iterator) {
     922           0 :       FATAL("Failed to create ICU break iterator, are ICU data files missing?");
     923             :     }
     924             : 
     925             :     // Set resolved settings (locale).
     926             :     SetResolvedBreakIteratorSettings(isolate, no_extension_locale,
     927           0 :                                      break_iterator, resolved);
     928             :   } else {
     929             :     SetResolvedBreakIteratorSettings(isolate, icu_locale, break_iterator,
     930         176 :                                      resolved);
     931             :   }
     932             : 
     933             :   DCHECK_NOT_NULL(break_iterator);
     934             : 
     935             :   Handle<JSFunction> constructor(
     936         352 :       isolate->native_context()->intl_v8_break_iterator_function());
     937             : 
     938             :   Handle<Object> br_object;
     939         352 :   ASSIGN_RETURN_ON_EXCEPTION(isolate, br_object,
     940             :                              JSObject::New(constructor, constructor),
     941             :                              JSIntlV8BreakIterator);
     942             :   Handle<JSIntlV8BreakIterator> br(
     943             :       reinterpret_cast<JSIntlV8BreakIterator*>(*br_object));
     944             : 
     945             :   br->set_break_iterator(break_iterator);
     946             :   br->set_unicode_string(nullptr);
     947             : 
     948             :   // Make object handle weak so we can delete the data format once GC kicks in.
     949             :   Handle<Object> wrapper = isolate->global_handles()->Create(*br);
     950             :   GlobalHandles::MakeWeak(wrapper.location(), wrapper.location(),
     951             :                           JSIntlV8BreakIterator::Delete,
     952         176 :                           WeakCallbackType::kFinalizer);
     953             : 
     954         176 :   return br;
     955             : }
     956             : 
     957           8 : void JSIntlV8BreakIterator::Delete(const v8::WeakCallbackInfo<void>& data) {
     958             :   Object** wrapper = reinterpret_cast<Object**>(data.GetParameter());
     959             :   JSIntlV8BreakIterator* br =
     960           8 :       reinterpret_cast<JSIntlV8BreakIterator*>(*wrapper);
     961           8 :   delete br->break_iterator();
     962           8 :   delete br->unicode_string();
     963           8 :   GlobalHandles::Destroy(wrapper);
     964           8 : }
     965             : 
     966             : }  // namespace internal
     967             : }  // namespace v8

Generated by: LCOV version 1.10