Commit ab722736 authored by Nebojsa Ciric's avatar Nebojsa Ciric Committed by Commit Bot

Implementing Intl.Locale proposal.

https://github.com/tc39/proposal-intl-locale

Rename locale property to baseName to better reflect the intented use case and the change in spec.

TBR: bmeurer@chromium.org
Bug: v8:7684
Cq-Include-Trybots: luci.v8.try:v8_linux_noi18n_rel_ng
Change-Id: I91b630b49ce73abcebd6040ec968c91d75cff879
Reviewed-on: https://chromium-review.googlesource.com/1014411
Commit-Queue: Sathya Gunasekaran <gsathya@chromium.org>
Reviewed-by: 's avatarSathya Gunasekaran <gsathya@chromium.org>
Cr-Commit-Position: refs/heads/master@{#53193}
parent aca33312
......@@ -2087,6 +2087,9 @@ v8_source_set("v8_base") {
"src/objects/js-array.h",
"src/objects/js-collection-inl.h",
"src/objects/js-collection.h",
"src/objects/js-locale-inl.h",
"src/objects/js-locale.cc",
"src/objects/js-locale.h",
"src/objects/js-promise-inl.h",
"src/objects/js-promise.h",
"src/objects/js-regexp-inl.h",
......@@ -2761,6 +2764,9 @@ v8_source_set("v8_base") {
"src/intl.h",
"src/objects/intl-objects.cc",
"src/objects/intl-objects.h",
"src/objects/js-locale-inl.h",
"src/objects/js-locale.cc",
"src/objects/js-locale.h",
"src/runtime/runtime-intl.cc",
]
}
......
......@@ -20,16 +20,16 @@
#include "src/heap/heap.h"
#include "src/isolate-inl.h"
#include "src/objects/api-callbacks.h"
#ifdef V8_INTL_SUPPORT
#include "src/objects/intl-objects.h"
#include "src/objects/js-locale.h"
#endif // V8_INTL_SUPPORT
#include "src/objects/js-regexp.h"
#include "src/objects/templates.h"
#include "src/snapshot/natives.h"
#include "src/snapshot/snapshot.h"
#include "src/wasm/wasm-js.h"
#if V8_INTL_SUPPORT
#include "src/objects/intl-objects.h"
#endif // V8_INTL_SUPPORT
namespace v8 {
namespace internal {
......@@ -4455,6 +4455,62 @@ void Genesis::InitializeGlobal_harmony_bigint() {
Builtins::kDataViewPrototypeSetBigUint64, 2, false);
}
#ifdef V8_INTL_SUPPORT
void Genesis::InitializeGlobal_harmony_locale() {
if (!FLAG_harmony_locale) return;
Handle<JSObject> intl = Handle<JSObject>::cast(
JSReceiver::GetProperty(
Handle<JSReceiver>(native_context()->global_object()),
factory()->InternalizeUtf8String("Intl"))
.ToHandleChecked());
Handle<JSFunction> locale_fun = InstallFunction(
intl, "Locale", JS_INTL_LOCALE_TYPE, JSLocale::kSize, 0,
factory()->the_hole_value(), Builtins::kLocaleConstructor);
InstallWithIntrinsicDefaultProto(isolate(), locale_fun,
Context::INTL_LOCALE_FUNCTION_INDEX);
locale_fun->shared()->set_length(1);
locale_fun->shared()->DontAdaptArguments();
// Setup %LocalePrototype%.
Handle<JSObject> prototype(JSObject::cast(locale_fun->instance_prototype()));
// Install the @@toStringTag property on the {prototype}.
JSObject::AddProperty(prototype, factory()->to_string_tag_symbol(),
factory()->NewStringFromAsciiChecked("Locale"),
static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY));
SimpleInstallFunction(prototype, "toString",
Builtins::kLocalePrototypeToString, 0, false);
// Base locale getters.
SimpleInstallGetter(prototype, factory()->InternalizeUtf8String("language"),
Builtins::kLocalePrototypeLanguage, true);
SimpleInstallGetter(prototype, factory()->InternalizeUtf8String("script"),
Builtins::kLocalePrototypeScript, true);
SimpleInstallGetter(prototype, factory()->InternalizeUtf8String("region"),
Builtins::kLocalePrototypeRegion, true);
SimpleInstallGetter(prototype, factory()->InternalizeUtf8String("baseName"),
Builtins::kLocalePrototypeBaseName, true);
// Unicode extension getters.
SimpleInstallGetter(prototype, factory()->InternalizeUtf8String("calendar"),
Builtins::kLocalePrototypeCalendar, true);
SimpleInstallGetter(prototype, factory()->InternalizeUtf8String("caseFirst"),
Builtins::kLocalePrototypeCaseFirst, true);
SimpleInstallGetter(prototype, factory()->InternalizeUtf8String("collation"),
Builtins::kLocalePrototypeCollation, true);
SimpleInstallGetter(prototype, factory()->InternalizeUtf8String("hourCycle"),
Builtins::kLocalePrototypeHourCycle, true);
SimpleInstallGetter(prototype, factory()->InternalizeUtf8String("numeric"),
Builtins::kLocalePrototypeNumeric, true);
SimpleInstallGetter(prototype,
factory()->InternalizeUtf8String("numberingSystem"),
Builtins::kLocalePrototypeNumberingSystem, true);
}
#endif // V8_INTL_SUPPORT
Handle<JSFunction> Genesis::CreateArrayBuffer(
Handle<String> name, ArrayBufferKind array_buffer_kind) {
// Create the %ArrayBufferPrototype%
......
......@@ -1287,7 +1287,20 @@ namespace internal {
/* ecma402 #sec-intl.numberformat.prototype.formattoparts */ \
CPP(NumberFormatPrototypeFormatToParts) \
/* ecma402 #sec-intl.datetimeformat.prototype.formattoparts */ \
CPP(DateTimeFormatPrototypeFormatToParts)
CPP(DateTimeFormatPrototypeFormatToParts) \
/* ecma402 #new proposal */ \
CPP(LocaleConstructor) \
CPP(LocalePrototypeLanguage) \
CPP(LocalePrototypeScript) \
CPP(LocalePrototypeRegion) \
CPP(LocalePrototypeBaseName) \
CPP(LocalePrototypeCalendar) \
CPP(LocalePrototypeCaseFirst) \
CPP(LocalePrototypeCollation) \
CPP(LocalePrototypeHourCycle) \
CPP(LocalePrototypeNumeric) \
CPP(LocalePrototypeNumberingSystem) \
CPP(LocalePrototypeToString)
#else
#define BUILTIN_LIST(CPP, API, TFJ, TFC, TFS, TFH, ASM) \
BUILTIN_LIST_BASE(CPP, API, TFJ, TFC, TFS, TFH, ASM) \
......
......@@ -13,6 +13,7 @@
#include "src/intl.h"
#include "src/objects-inl.h"
#include "src/objects/intl-objects.h"
#include "src/objects/js-locale-inl.h"
#include "unicode/datefmt.h"
#include "unicode/decimfmt.h"
......@@ -505,5 +506,138 @@ BUILTIN(DateTimeFormatPrototypeFormatToParts) {
return FormatDateToParts(isolate, date_format, date_value);
}
// Intl.Locale implementation
BUILTIN(LocaleConstructor) {
HandleScope scope(isolate);
if (args.new_target()->IsUndefined(isolate)) { // [[Call]]
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kConstructorNotFunction,
isolate->factory()->NewStringFromAsciiChecked(
"Intl.Locale")));
} else { // [[Construct]]
Handle<JSFunction> target = args.target();
Handle<JSReceiver> new_target = Handle<JSReceiver>::cast(args.new_target());
Handle<JSObject> result;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
JSObject::New(target, new_target));
Handle<Object> tag = args.atOrUndefined(isolate, 1);
Handle<Object> options = args.atOrUndefined(isolate, 2);
// First parameter is a locale, as a string/object. Can't be empty.
if (!tag->IsName() && !tag->IsJSReceiver()) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kLocaleNotEmpty));
}
Handle<String> locale_string;
if (tag->IsJSLocale() &&
Handle<JSLocale>::cast(tag)->locale()->IsString()) {
locale_string = Handle<String>(Handle<JSLocale>::cast(tag)->locale());
} else {
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, locale_string,
Object::ToString(isolate, tag));
}
Handle<JSReceiver> options_object;
if (options->IsNullOrUndefined(isolate)) {
// Make empty options bag.
options_object = isolate->factory()->NewJSObjectWithNullProto();
} else {
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, options_object,
Object::ToObject(isolate, options));
}
if (!JSLocale::InitializeLocale(isolate, Handle<JSLocale>::cast(result),
locale_string, options_object)) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kLocaleBadParameters));
}
return *result;
}
}
// Locale getters.
BUILTIN(LocalePrototypeLanguage) {
HandleScope scope(isolate);
// CHECK_RECEIVER will case locale_holder to JSLocale.
CHECK_RECEIVER(JSLocale, locale_holder, "Intl.Locale.prototype.language");
return locale_holder->language();
}
BUILTIN(LocalePrototypeScript) {
HandleScope scope(isolate);
CHECK_RECEIVER(JSLocale, locale_holder, "Intl.Locale.prototype.script");
return locale_holder->script();
}
BUILTIN(LocalePrototypeRegion) {
HandleScope scope(isolate);
CHECK_RECEIVER(JSLocale, locale_holder, "Intl.Locale.prototype.region");
return locale_holder->region();
}
BUILTIN(LocalePrototypeBaseName) {
HandleScope scope(isolate);
CHECK_RECEIVER(JSLocale, locale_holder, "Intl.Locale.prototype.baseName");
return locale_holder->base_name();
}
BUILTIN(LocalePrototypeCalendar) {
HandleScope scope(isolate);
CHECK_RECEIVER(JSLocale, locale_holder, "Intl.Locale.prototype.calendar");
return locale_holder->calendar();
}
BUILTIN(LocalePrototypeCaseFirst) {
HandleScope scope(isolate);
CHECK_RECEIVER(JSLocale, locale_holder, "Intl.Locale.prototype.caseFirst");
return locale_holder->case_first();
}
BUILTIN(LocalePrototypeCollation) {
HandleScope scope(isolate);
CHECK_RECEIVER(JSLocale, locale_holder, "Intl.Locale.prototype.collation");
return locale_holder->collation();
}
BUILTIN(LocalePrototypeHourCycle) {
HandleScope scope(isolate);
CHECK_RECEIVER(JSLocale, locale_holder, "Intl.Locale.prototype.hourCycle");
return locale_holder->hour_cycle();
}
BUILTIN(LocalePrototypeNumeric) {
HandleScope scope(isolate);
CHECK_RECEIVER(JSLocale, locale_holder, "Intl.Locale.prototype.numeric");
return locale_holder->numeric();
}
BUILTIN(LocalePrototypeNumberingSystem) {
HandleScope scope(isolate);
CHECK_RECEIVER(JSLocale, locale_holder,
"Intl.Locale.prototype.numberingSystem");
return locale_holder->numbering_system();
}
BUILTIN(LocalePrototypeToString) {
HandleScope scope(isolate);
CHECK_RECEIVER(JSLocale, locale_holder, "Intl.Locale.prototype.toString");
return locale_holder->locale();
}
} // namespace internal
} // namespace v8
......@@ -216,6 +216,9 @@ Type::bitset BitsetType::Lub(i::Map* map) {
case JS_VALUE_TYPE:
case JS_MESSAGE_OBJECT_TYPE:
case JS_DATE_TYPE:
#ifdef V8_INTL_SUPPORT
case JS_INTL_LOCALE_TYPE:
#endif // V8_INTL_SUPPORT
case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
case JS_GENERATOR_OBJECT_TYPE:
case JS_ASYNC_GENERATOR_OBJECT_TYPE:
......
......@@ -22,7 +22,6 @@ enum ContextLookupFlags {
FOLLOW_CHAINS = FOLLOW_CONTEXT_CHAIN | FOLLOW_PROTOTYPE_CHAIN,
};
// Heap-allocated activation contexts.
//
// Contexts are implemented as FixedArray objects; the Context
......@@ -203,6 +202,7 @@ enum ContextLookupFlags {
intl_date_time_format_function) \
V(INTL_NUMBER_FORMAT_FUNCTION_INDEX, JSFunction, \
intl_number_format_function) \
V(INTL_LOCALE_FUNCTION_INDEX, JSFunction, intl_locale_function) \
V(INTL_COLLATOR_FUNCTION_INDEX, JSFunction, intl_collator_function) \
V(INTL_PLURAL_RULES_FUNCTION_INDEX, JSFunction, intl_plural_rules_function) \
V(INTL_V8_BREAK_ITERATOR_FUNCTION_INDEX, JSFunction, \
......@@ -434,7 +434,7 @@ class ScriptContextTable : public FixedArray {
// Script contexts from all top-level scripts are gathered in
// ScriptContextTable.
class Context: public FixedArray {
class Context : public FixedArray {
public:
// Conversions.
static inline Context* cast(Object* context);
......@@ -451,7 +451,7 @@ class Context: public FixedArray {
EXTENSION_INDEX,
NATIVE_CONTEXT_INDEX,
// These slots are only in native contexts.
// These slots are only in native contexts.
#define NATIVE_CONTEXT_SLOT(index, type, name) index,
NATIVE_CONTEXT_FIELDS(NATIVE_CONTEXT_SLOT)
#undef NATIVE_CONTEXT_SLOT
......
......@@ -208,12 +208,20 @@ DEFINE_IMPLICATION(harmony_class_fields, harmony_private_fields)
// Update bootstrapper.cc whenever adding a new feature flag.
// Features that are still work in progress (behind individual flags).
#define HARMONY_INPROGRESS(V) \
#define HARMONY_INPROGRESS_BASE(V) \
V(harmony_do_expressions, "harmony do-expressions") \
V(harmony_class_fields, "harmony fields in class literals") \
V(harmony_static_fields, "harmony static fields in class literals") \
V(harmony_array_flatten, "harmony Array.prototype.flat{ten,Map}")
#ifdef V8_INTL_SUPPORT
#define HARMONY_INPROGRESS(V) \
HARMONY_INPROGRESS_BASE(V) \
V(harmony_locale, "Intl.Locale")
#else
#define HARMONY_INPROGRESS(V) HARMONY_INPROGRESS_BASE(V)
#endif
// Features that are complete (but still behind --harmony/es-staging flag).
#define HARMONY_STAGED(V) \
V(harmony_restrict_constructor_return, \
......
......@@ -341,6 +341,9 @@ class ErrorUtils : public AllStatic {
T(IteratorSymbolNonCallable, "Found non-callable @@iterator") \
T(IteratorValueNotAnObject, "Iterator value % is not an entry object") \
T(LanguageID, "Language ID should be string or object.") \
T(LocaleNotEmpty, \
"First argument to Intl.Locale constructor can't be empty or missing") \
T(LocaleBadParameters, "Incorrect locale information provided") \
T(MapperFunctionNonCallable, "flatMap mapper function is not callable") \
T(MethodCalledOnWrongObject, \
"Method % called on a non-object or on a wrong type of object.") \
......
......@@ -620,6 +620,9 @@ ReturnType BodyDescriptorApply(InstanceType type, T1 p1, T2 p2, T3 p3, T4 p4) {
case JS_SPECIAL_API_OBJECT_TYPE:
case JS_MESSAGE_OBJECT_TYPE:
case JS_BOUND_FUNCTION_TYPE:
#ifdef V8_INTL_SUPPORT
case JS_INTL_LOCALE_TYPE:
#endif // V8_INTL_SUPPORT
case WASM_GLOBAL_TYPE:
case WASM_MEMORY_TYPE:
case WASM_MODULE_TYPE:
......
......@@ -17,6 +17,9 @@
#include "src/objects/data-handler-inl.h"
#include "src/objects/debug-objects-inl.h"
#include "src/objects/literal-objects.h"
#ifdef V8_INTL_SUPPORT
#include "src/objects/js-locale-inl.h"
#endif // V8_INTL_SUPPORT
#include "src/objects/maybe-object.h"
#include "src/objects/microtask-inl.h"
#include "src/objects/module.h"
......@@ -314,6 +317,11 @@ void HeapObject::HeapObjectVerify() {
case CODE_DATA_CONTAINER_TYPE:
CodeDataContainer::cast(this)->CodeDataContainerVerify();
break;
#ifdef V8_INTL_SUPPORT
case JS_INTL_LOCALE_TYPE:
JSLocale::cast(this)->JSLocaleVerify();
break;
#endif // V8_INTL_SUPPORT
#define MAKE_STRUCT_CASE(NAME, Name, name) \
case NAME##_TYPE: \
......@@ -1771,6 +1779,23 @@ void InterpreterData::InterpreterDataVerify() {
CHECK(interpreter_trampoline()->IsCode());
}
#ifdef V8_INTL_SUPPORT
void JSLocale::JSLocaleVerify() {
VerifyObjectField(kLanguageOffset);
VerifyObjectField(kScriptOffset);
VerifyObjectField(kRegionOffset);
VerifyObjectField(kBaseNameOffset);
VerifyObjectField(kLocaleOffset);
// Unicode extension fields.
VerifyObjectField(kCalendarOffset);
VerifyObjectField(kCaseFirstOffset);
VerifyObjectField(kCollationOffset);
VerifyObjectField(kHourCycleOffset);
VerifyObjectField(kNumericOffset);
VerifyObjectField(kNumberingSystemOffset);
}
#endif // V8_INTL_SUPPORT
#endif // VERIFY_HEAP
#ifdef DEBUG
......
......@@ -103,6 +103,9 @@ TYPE_CHECKER(JSDate, JS_DATE_TYPE)
TYPE_CHECKER(JSError, JS_ERROR_TYPE)
TYPE_CHECKER(JSFunction, JS_FUNCTION_TYPE)
TYPE_CHECKER(JSGlobalObject, JS_GLOBAL_OBJECT_TYPE)
#ifdef V8_INTL_SUPPORT
TYPE_CHECKER(JSLocale, JS_INTL_LOCALE_TYPE)
#endif // V8_INTL_SUPPORT
TYPE_CHECKER(JSMessageObject, JS_MESSAGE_OBJECT_TYPE)
TYPE_CHECKER(JSStringIterator, JS_STRING_ITERATOR_TYPE)
TYPE_CHECKER(JSValue, JS_VALUE_TYPE)
......
......@@ -13,6 +13,9 @@
#include "src/interpreter/bytecodes.h"
#include "src/objects-inl.h"
#include "src/objects/debug-objects-inl.h"
#ifdef V8_INTL_SUPPORT
#include "src/objects/js-locale-inl.h"
#endif // V8_INTL_SUPPORT
#include "src/objects/microtask-inl.h"
#include "src/objects/promise-inl.h"
#include "src/ostreams.h"
......@@ -257,6 +260,11 @@ void HeapObject::HeapObjectPrint(std::ostream& os) { // NOLINT
case JS_DATA_VIEW_TYPE:
JSDataView::cast(this)->JSDataViewPrint(os);
break;
#ifdef V8_INTL_SUPPORT
case JS_INTL_LOCALE_TYPE:
JSLocale::cast(this)->JSLocalePrint(os);
break;
#endif // V8_INTL_SUPPORT
#define MAKE_STRUCT_CASE(NAME, Name, name) \
case NAME##_TYPE: \
Name::cast(this)->Name##Print(os); \
......@@ -1840,6 +1848,24 @@ void Script::ScriptPrint(std::ostream& os) { // NOLINT
os << "\n";
}
#ifdef V8_INTL_SUPPORT
void JSLocale::JSLocalePrint(std::ostream& os) { // NOLINT
HeapObject::PrintHeader(os, "JSLocale");
os << "\n - language: " << Brief(language());
os << "\n - script: " << Brief(script());
os << "\n - region: " << Brief(region());
os << "\n - baseName: " << Brief(base_name());
os << "\n - locale: " << Brief(locale());
os << "\n - calendar: " << Brief(calendar());
os << "\n - caseFirst: " << Brief(case_first());
os << "\n - collation: " << Brief(collation());
os << "\n - hourCycle: " << Brief(hour_cycle());
os << "\n - numeric: " << Brief(numeric());
os << "\n - numberingSystem: " << Brief(numbering_system());
os << "\n";
}
#endif // V8_INTL_SUPPORT
namespace {
void PrintScopeInfoList(ScopeInfo* scope_info, std::ostream& os,
const char* list_name, int nof_internal_slots,
......
......@@ -60,6 +60,9 @@
#include "src/objects/debug-objects-inl.h"
#include "src/objects/frame-array-inl.h"
#include "src/objects/hash-table.h"
#ifdef V8_INTL_SUPPORT
#include "src/objects/js-locale.h"
#endif // V8_INTL_SUPPORT
#include "src/objects/js-regexp-string-iterator.h"
#include "src/objects/map.h"
#include "src/objects/microtask-inl.h"
......@@ -1394,6 +1397,10 @@ int JSObject::GetHeaderSize(InstanceType type,
return JSStringIterator::kSize;
case JS_MODULE_NAMESPACE_TYPE:
return JSModuleNamespace::kHeaderSize;
#ifdef V8_INTL_SUPPORT
case JS_INTL_LOCALE_TYPE:
return JSLocale::kSize;
#endif // V8_INTL_SUPPORT
case WASM_GLOBAL_TYPE:
return WasmGlobalObject::kSize;
case WASM_INSTANCE_TYPE:
......@@ -3078,6 +3085,9 @@ VisitorId Map::GetVisitorId(Map* map) {
case JS_PROMISE_TYPE:
case JS_REGEXP_TYPE:
case JS_REGEXP_STRING_ITERATOR_TYPE:
#ifdef V8_INTL_SUPPORT
case JS_INTL_LOCALE_TYPE:
#endif // V8_INTL_SUPPORT
case WASM_GLOBAL_TYPE:
case WASM_MEMORY_TYPE:
case WASM_MODULE_TYPE:
......
This diff is collapsed.
// Copyright 2018 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_INTL_SUPPORT
#error Internationalization is expected to be enabled.
#endif // V8_INTL_SUPPORT
#ifndef V8_OBJECTS_JS_LOCALE_INL_H_
#define V8_OBJECTS_JS_LOCALE_INL_H_
#include "src/objects-inl.h"
#include "src/objects/js-locale.h"
// Has to be the last include (doesn't have include guards):
#include "src/objects/object-macros.h"
namespace v8 {
namespace internal {
// Base locale accessors.
ACCESSORS(JSLocale, language, Object, kLanguageOffset);
ACCESSORS(JSLocale, script, Object, kScriptOffset);
ACCESSORS(JSLocale, region, Object, kRegionOffset);
ACCESSORS(JSLocale, base_name, Object, kBaseNameOffset);
ACCESSORS(JSLocale, locale, String, kLocaleOffset);
// Unicode extension accessors.
ACCESSORS(JSLocale, calendar, Object, kCalendarOffset);
ACCESSORS(JSLocale, case_first, Object, kCaseFirstOffset);
ACCESSORS(JSLocale, collation, Object, kCollationOffset);
ACCESSORS(JSLocale, hour_cycle, Object, kHourCycleOffset);
ACCESSORS(JSLocale, numeric, Object, kNumericOffset);
ACCESSORS(JSLocale, numbering_system, Object, kNumberingSystemOffset);
CAST_ACCESSOR(JSLocale);
} // namespace internal
} // namespace v8
#endif // V8_OBJECTS_JS_LOCALE_INL_H_
// Copyright 2018 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_INTL_SUPPORT
#error Internationalization is expected to be enabled.
#endif // V8_INTL_SUPPORT
#include "src/objects/js-locale.h"
#include <map>
#include <memory>
#include <string>
#include "src/api.h"
#include "src/global-handles.h"
#include "src/heap/factory.h"
#include "src/isolate.h"
#include "src/objects-inl.h"
#include "src/objects/js-locale-inl.h"
#include "unicode/locid.h"
#include "unicode/unistr.h"
#include "unicode/uvernum.h"
#include "unicode/uversion.h"
#if U_ICU_VERSION_MAJOR_NUM >= 59
#include "unicode/char16ptr.h"
#endif
namespace v8 {
namespace internal {
namespace {
// gcc has problem with constexpr here, so falling back to const.
const std::array<std::pair<const char*, const char*>, 6>
kOptionToUnicodeTagMap = {{{"calendar", "ca"},
{"collation", "co"},
{"hourCycle", "hc"},
{"caseFirst", "kf"},
{"numeric", "kn"},
{"numberingSystem", "nu"}}};
// Extracts value of a given property key in the Object.
Maybe<bool> ExtractStringSetting(Isolate* isolate, Handle<JSReceiver> options,
const char* key, icu::UnicodeString* setting) {
v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
Handle<String> str = isolate->factory()->NewStringFromAsciiChecked(key);
// JSReceiver::GetProperty could throw an exception and return an empty
// MaybeHandle<Object>().
// Returns Nothing<bool> on exception.
Handle<Object> object;
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate, object, JSReceiver::GetProperty(options, str), Nothing<bool>());
if (object->IsString()) {
v8::String::Utf8Value utf8_string(
v8_isolate, v8::Utils::ToLocal(Handle<String>::cast(object)));
*setting = icu::UnicodeString::fromUTF8(*utf8_string);
return Just(true);
}
return Just(false);
}
// Inserts tags from options into locale string.
Maybe<bool> InsertOptionsIntoLocale(Isolate* isolate,
Handle<JSReceiver> options,
char* icu_locale) {
CHECK(isolate);
CHECK(icu_locale);
for (const auto& option_to_bcp47 : kOptionToUnicodeTagMap) {
UErrorCode status = U_ZERO_ERROR;
icu::UnicodeString value_unicode;
Maybe<bool> found = ExtractStringSetting(
isolate, options, option_to_bcp47.first, &value_unicode);
// Return on exception.
MAYBE_RETURN(found, Nothing<bool>());
if (!found.FromJust()) {
// Skip this key, user didn't specify it in options.
continue;
}
DCHECK(found.FromJust());
std::string value_string;
value_unicode.toUTF8String(value_string);
// Convert bcp47 key and value into legacy ICU format so we can use
// uloc_setKeywordValue.
const char* key = uloc_toLegacyKey(option_to_bcp47.second);
if (!key) return Just(false);
// Overwrite existing, or insert new key-value to the locale string.
const char* value = uloc_toLegacyType(key, value_string.c_str());
if (value) {
// TODO(cira): ICU puts artificial limit on locale length, while BCP47
// doesn't. Switch to C++ API when it's ready.
// Related ICU bug - https://ssl.icu-project.org/trac/ticket/13417.
uloc_setKeywordValue(key, value, icu_locale, ULOC_FULLNAME_CAPACITY,
&status);
if (U_FAILURE(status) || status == U_STRING_NOT_TERMINATED_WARNING) {
return Just(false);
}
} else {
return Just(false);
}
}
return Just(true);
}
// Fills in the JSLocale object slots with Unicode tag/values.
bool PopulateLocaleWithUnicodeTags(Isolate* isolate, const char* icu_locale,
Handle<JSLocale> locale_holder) {
CHECK(isolate);
CHECK(icu_locale);
Factory* factory = isolate->factory();
static std::map<std::string, std::string> bcp47_to_option_map;
for (const auto& option_to_bcp47 : kOptionToUnicodeTagMap) {
bcp47_to_option_map.emplace(option_to_bcp47.second, option_to_bcp47.first);
}
UErrorCode status = U_ZERO_ERROR;
UEnumeration* keywords = uloc_openKeywords(icu_locale, &status);
if (!keywords) return true;
char value[ULOC_FULLNAME_CAPACITY];
while (const char* keyword = uenum_next(keywords, nullptr, &status)) {
uloc_getKeywordValue(icu_locale, keyword, value, ULOC_FULLNAME_CAPACITY,
&status);
if (U_FAILURE(status)) {
status = U_ZERO_ERROR;
continue;
}
// Ignore those we don't recognize - spec allows that.
const char* bcp47_key = uloc_toUnicodeLocaleKey(keyword);
if (bcp47_key) {
const char* bcp47_value = uloc_toUnicodeLocaleType(bcp47_key, value);
if (bcp47_value) {
auto iterator = bcp47_to_option_map.find(bcp47_key);
if (iterator != bcp47_to_option_map.end()) {
// It's either Boolean value.
if (iterator->second == "numeric") {
bool numeric = strcmp(bcp47_value, "true") == 0 ? true : false;
Handle<Object> numeric_handle = factory->ToBoolean(numeric);
locale_holder->set_numeric(*numeric_handle);
continue;
}
// Or a string.
Handle<String> bcp47_handle =
factory->NewStringFromAsciiChecked(bcp47_value);
if (iterator->second == "calendar") {
locale_holder->set_calendar(*bcp47_handle);
} else if (iterator->second == "caseFirst") {
locale_holder->set_case_first(*bcp47_handle);
} else if (iterator->second == "collation") {
locale_holder->set_collation(*bcp47_handle);
} else if (iterator->second == "hourCycle") {
locale_holder->set_hour_cycle(*bcp47_handle);
} else if (iterator->second == "numberingSystem") {
locale_holder->set_numbering_system(*bcp47_handle);
}
}
}
}
}
uenum_close(keywords);
return true;
}
} // namespace
bool JSLocale::InitializeLocale(Isolate* isolate,
Handle<JSLocale> locale_holder,
Handle<String> locale,
Handle<JSReceiver> options) {
v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
UErrorCode status = U_ZERO_ERROR;
// Get ICU locale format, and canonicalize it.
char icu_result[ULOC_FULLNAME_CAPACITY];
char icu_canonical[ULOC_FULLNAME_CAPACITY];
v8::String::Utf8Value bcp47_locale(v8_isolate, v8::Utils::ToLocal(locale));
if (bcp47_locale.length() == 0) return false;
int icu_length = uloc_forLanguageTag(
*bcp47_locale, icu_result, ULOC_FULLNAME_CAPACITY, nullptr, &status);
if (U_FAILURE(status) || status == U_STRING_NOT_TERMINATED_WARNING ||
icu_length == 0) {
return false;
}
Maybe<bool> error = InsertOptionsIntoLocale(isolate, options, icu_result);
if (error.IsNothing() || !error.FromJust()) {
return false;
}
uloc_canonicalize(icu_result, icu_canonical, ULOC_FULLNAME_CAPACITY, &status);
if (U_FAILURE(status) || status == U_STRING_NOT_TERMINATED_WARNING) {
return false;
}
if (!PopulateLocaleWithUnicodeTags(isolate, icu_canonical, locale_holder)) {
return false;
}
// Extract language, script and region parts.
char icu_language[ULOC_LANG_CAPACITY];
uloc_getLanguage(icu_canonical, icu_language, ULOC_LANG_CAPACITY, &status);
char icu_script[ULOC_SCRIPT_CAPACITY];
uloc_getScript(icu_canonical, icu_script, ULOC_SCRIPT_CAPACITY, &status);
char icu_region[ULOC_COUNTRY_CAPACITY];
uloc_getCountry(icu_canonical, icu_region, ULOC_COUNTRY_CAPACITY, &status);
if (U_FAILURE(status) || status == U_STRING_NOT_TERMINATED_WARNING) {
return false;
}
Factory* factory = isolate->factory();
// NOTE: One shouldn't use temporary handles, because they can go out of
// scope and be garbage collected before properly assigned.
// DON'T DO THIS: locale_holder->set_language(*f->NewStringAscii...);
Handle<String> language = factory->NewStringFromAsciiChecked(icu_language);
locale_holder->set_language(*language);
if (strlen(icu_script) != 0) {
Handle<String> script = factory->NewStringFromAsciiChecked(icu_script);
locale_holder->set_script(*script);
}
if (strlen(icu_region) != 0) {
Handle<String> region = factory->NewStringFromAsciiChecked(icu_region);
locale_holder->set_region(*region);
}
char icu_base_name[ULOC_FULLNAME_CAPACITY];
uloc_getBaseName(icu_canonical, icu_base_name, ULOC_FULLNAME_CAPACITY,
&status);
// We need to convert it back to BCP47.
char bcp47_result[ULOC_FULLNAME_CAPACITY];
uloc_toLanguageTag(icu_base_name, bcp47_result, ULOC_FULLNAME_CAPACITY, true,
&status);
if (U_FAILURE(status) || status == U_STRING_NOT_TERMINATED_WARNING) {
return false;
}
Handle<String> base_name = factory->NewStringFromAsciiChecked(bcp47_result);
locale_holder->set_base_name(*base_name);
// Produce final representation of the locale string, for toString().
uloc_toLanguageTag(icu_canonical, bcp47_result, ULOC_FULLNAME_CAPACITY, true,
&status);
if (U_FAILURE(status) || status == U_STRING_NOT_TERMINATED_WARNING) {
return false;
}
Handle<String> locale_handle =
factory->NewStringFromAsciiChecked(bcp47_result);
locale_holder->set_locale(*locale_handle);
return true;
}
} // namespace internal
} // namespace v8
// Copyright 2018 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_INTL_SUPPORT
#error Internationalization is expected to be enabled.
#endif // V8_INTL_SUPPORT
#ifndef V8_OBJECTS_JS_LOCALE_H_
#define V8_OBJECTS_JS_LOCALE_H_
#include "src/api.h"
#include "src/global-handles.h"
#include "src/heap/factory.h"
#include "src/isolate.h"
#include "src/objects.h"
#include "unicode/unistr.h"
// Has to be the last include (doesn't have include guards):
#include "src/objects/object-macros.h"
namespace v8 {
namespace internal {
class JSLocale : public JSObject {
public:
// Initializes locale object with properties derived from input locale string
// and options.
static bool InitializeLocale(Isolate* isolate, Handle<JSLocale> locale_holder,
Handle<String> locale,
Handle<JSReceiver> options);
DECL_CAST(JSLocale)
// Locale accessors.
DECL_ACCESSORS(language, Object)
DECL_ACCESSORS(script, Object)
DECL_ACCESSORS(region, Object)
DECL_ACCESSORS(base_name, Object)
DECL_ACCESSORS(locale, String)
// Unicode extension accessors.
DECL_ACCESSORS(calendar, Object)
DECL_ACCESSORS(case_first, Object)
DECL_ACCESSORS(collation, Object)
DECL_ACCESSORS(hour_cycle, Object)
DECL_ACCESSORS(numeric, Object)
DECL_ACCESSORS(numbering_system, Object)
DECL_PRINTER(JSLocale)
DECL_VERIFIER(JSLocale)
// Layout description.
static const int kJSLocaleOffset = JSObject::kHeaderSize;
// Locale fields.
static const int kLanguageOffset = kJSLocaleOffset + kPointerSize;
static const int kScriptOffset = kLanguageOffset + kPointerSize;
static const int kRegionOffset = kScriptOffset + kPointerSize;
static const int kBaseNameOffset = kRegionOffset + kPointerSize;
static const int kLocaleOffset = kBaseNameOffset + kPointerSize;
// Unicode extension fields.
static const int kCalendarOffset = kLocaleOffset + kPointerSize;
static const int kCaseFirstOffset = kCalendarOffset + kPointerSize;
static const int kCollationOffset = kCaseFirstOffset + kPointerSize;
static const int kHourCycleOffset = kCollationOffset + kPointerSize;
static const int kNumericOffset = kHourCycleOffset + kPointerSize;
static const int kNumberingSystemOffset = kNumericOffset + kPointerSize;
// Final size.
static const int kSize = kNumberingSystemOffset + kPointerSize;
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(JSLocale);
};
} // namespace internal
} // namespace v8
#endif // V8_OBJECTS_JS_LOCALE_H_
......@@ -362,7 +362,7 @@ bytecodes: [
B(TestTypeOf), U8(6),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(145),
B(Wide), B(LdaSmi), I16(147),
B(Star), R(18),
B(LdaConstant), U8(14),
B(Star), R(19),
......
......@@ -123,7 +123,7 @@ bytecodes: [
B(TestTypeOf), U8(6),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(145),
B(Wide), B(LdaSmi), I16(147),
B(Star), R(19),
B(LdaConstant), U8(11),
B(Star), R(20),
......@@ -374,7 +374,7 @@ bytecodes: [
B(TestTypeOf), U8(6),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(145),
B(Wide), B(LdaSmi), I16(147),
B(Star), R(19),
B(LdaConstant), U8(11),
B(Star), R(20),
......@@ -647,7 +647,7 @@ bytecodes: [
B(TestTypeOf), U8(6),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(145),
B(Wide), B(LdaSmi), I16(147),
B(Star), R(19),
B(LdaConstant), U8(11),
B(Star), R(20),
......@@ -876,7 +876,7 @@ bytecodes: [
B(TestTypeOf), U8(6),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(145),
B(Wide), B(LdaSmi), I16(147),
B(Star), R(17),
B(LdaConstant), U8(9),
B(Star), R(18),
......
......@@ -85,7 +85,7 @@ bytecodes: [
B(TestTypeOf), U8(6),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(145),
B(Wide), B(LdaSmi), I16(147),
B(Star), R(12),
B(LdaConstant), U8(7),
B(Star), R(13),
......@@ -217,7 +217,7 @@ bytecodes: [
B(TestTypeOf), U8(6),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(145),
B(Wide), B(LdaSmi), I16(147),
B(Star), R(13),
B(LdaConstant), U8(7),
B(Star), R(14),
......@@ -361,7 +361,7 @@ bytecodes: [
B(TestTypeOf), U8(6),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(145),
B(Wide), B(LdaSmi), I16(147),
B(Star), R(12),
B(LdaConstant), U8(7),
B(Star), R(13),
......@@ -495,7 +495,7 @@ bytecodes: [
B(TestTypeOf), U8(6),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(145),
B(Wide), B(LdaSmi), I16(147),
B(Star), R(11),
B(LdaConstant), U8(9),
B(Star), R(12),
......
......@@ -89,7 +89,7 @@ bytecodes: [
B(TestTypeOf), U8(6),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(145),
B(Wide), B(LdaSmi), I16(147),
B(Star), R(14),
B(LdaConstant), U8(6),
B(Star), R(15),
......@@ -256,7 +256,7 @@ bytecodes: [
B(TestTypeOf), U8(6),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(145),
B(Wide), B(LdaSmi), I16(147),
B(Star), R(14),
B(LdaConstant), U8(11),
B(Star), R(15),
......@@ -401,7 +401,7 @@ bytecodes: [
B(TestTypeOf), U8(6),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(145),
B(Wide), B(LdaSmi), I16(147),
B(Star), R(12),
B(LdaConstant), U8(8),
B(Star), R(13),
......@@ -495,7 +495,7 @@ bytecodes: [
B(JumpIfUndefined), U8(6),
B(Ldar), R(6),
B(JumpIfNotNull), U8(16),
B(LdaSmi), I8(75),
B(LdaSmi), I8(77),
B(Star), R(18),
B(LdaConstant), U8(4),
B(Star), R(19),
......@@ -550,7 +550,7 @@ bytecodes: [
B(TestTypeOf), U8(6),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(145),
B(Wide), B(LdaSmi), I16(147),
B(Star), R(17),
B(LdaConstant), U8(8),
B(Star), R(18),
......@@ -702,7 +702,7 @@ bytecodes: [
B(TestTypeOf), U8(6),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(145),
B(Wide), B(LdaSmi), I16(147),
B(Star), R(16),
B(LdaConstant), U8(10),
B(Star), R(17),
......@@ -870,7 +870,7 @@ bytecodes: [
B(TestTypeOf), U8(6),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(145),
B(Wide), B(LdaSmi), I16(147),
B(Star), R(15),
B(LdaConstant), U8(13),
B(Star), R(16),
......@@ -1024,7 +1024,7 @@ bytecodes: [
B(TestTypeOf), U8(6),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(145),
B(Wide), B(LdaSmi), I16(147),
B(Star), R(21),
B(LdaConstant), U8(7),
B(Star), R(22),
......@@ -1238,7 +1238,7 @@ bytecodes: [
B(TestTypeOf), U8(6),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(145),
B(Wide), B(LdaSmi), I16(147),
B(Star), R(20),
B(LdaConstant), U8(8),
B(Star), R(21),
......
......@@ -203,7 +203,7 @@ bytecodes: [
B(TestTypeOf), U8(6),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(145),
B(Wide), B(LdaSmi), I16(147),
B(Star), R(14),
B(LdaConstant), U8(13),
B(Star), R(15),
......
......@@ -229,7 +229,7 @@ bytecodes: [
B(JumpIfUndefined), U8(6),
B(Ldar), R(3),
B(JumpIfNotNull), U8(16),
B(LdaSmi), I8(75),
B(LdaSmi), I8(77),
B(Star), R(4),
B(LdaConstant), U8(1),
B(Star), R(5),
......
// Copyright 2018 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --harmony-locale
// Make sure that locale string got canonicalized by the spec,
// keys are sorted and unique, region upper cased, script title cased and
// language lower cased.
let locale = new Intl.Locale('sr-cyrl-rs-t-ja-u-ca-islamic-x-whatever', {
calendar: 'buddhist',
caseFirst: 'true',
collation: 'phonebk',
hourCycle: 'h23',
caseFirst: 'upper',
numeric: 'true',
numberingSystem: 'roman'
});
let expected =
'sr-Cyrl-RS-t-ja-u-ca-buddhist-co-phonebk-hc-h23-kf-upper-kn-true-nu-roman-x-whatever';
assertEquals(expected, locale.toString());
// Copyright 2018 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --harmony-locale
// Locale constructor can't be called as function.
assertThrows(() => Intl.Locale('sr'), TypeError);
// Non-string locale.
assertThrows(() => new Intl.Locale(5), TypeError);
// Invalid locale.
assertThrows(() => new Intl.Locale('abcdefghi'), TypeError);
// Options will be force converted into Object.
assertDoesNotThrow(() => new Intl.Locale('sr', 5));
// ICU problem - locale length is limited.
// http://bugs.icu-project.org/trac/ticket/13417.
assertThrows(
() => new Intl.Locale(
'sr-cyrl-rs-t-ja-u-ca-islamic-cu-rsd-tz-uslax-x-whatever', {
calendar: 'buddhist',
caseFirst: 'true',
collation: 'phonebk',
hourCycle: 'h23',
caseFirst: 'upper',
numeric: 'true',
numberingSystem: 'roman',
}),
TypeError);
// Copyright 2018 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --harmony-locale
// Make sure that locale exposes all required properties. Those not specified
// should have undefined value.
let locale = new Intl.Locale('sr-cyrl-rs-t-ja-u-ca-islamic-x-whatever', {
calendar: 'buddhist',
caseFirst: 'true',
collation: 'phonebk',
hourCycle: 'h23',
caseFirst: 'upper',
numeric: 'true',
numberingSystem: 'roman'
});
assertEquals('sr', locale.language);
assertEquals('Cyrl', locale.script);
assertEquals('RS', locale.region);
assertEquals('sr-Cyrl-RS', locale.baseName);
assertEquals('buddhist', locale.calendar);
assertEquals('phonebk', locale.collation);
assertEquals('h23', locale.hourCycle);
assertEquals('upper', locale.caseFirst);
assertEquals(true, locale.numeric);
assertEquals('roman', locale.numberingSystem);
// Not defined, expected to undefined.
assertEquals(undefined, locale.currency);
assertEquals(undefined, locale.timeZone);
// Test property defined in spec, but not specified in locale.
let missing_property = new Intl.Locale('sr');
assertEquals(undefined, missing_property.script);
......@@ -148,13 +148,14 @@ INSTANCE_TYPES = {
1081: "JS_WEAK_SET_TYPE",
1082: "JS_TYPED_ARRAY_TYPE",
1083: "JS_DATA_VIEW_TYPE",
1084: "WASM_GLOBAL_TYPE",
1085: "WASM_INSTANCE_TYPE",
1086: "WASM_MEMORY_TYPE",
1087: "WASM_MODULE_TYPE",
1088: "WASM_TABLE_TYPE",
1089: "JS_BOUND_FUNCTION_TYPE",
1090: "JS_FUNCTION_TYPE",
1084: "JS_INTL_LOCALE_TYPE",
1085: "WASM_GLOBAL_TYPE",
1086: "WASM_INSTANCE_TYPE",
1087: "WASM_MEMORY_TYPE",
1088: "WASM_MODULE_TYPE",
1089: "WASM_TABLE_TYPE",
1090: "JS_BOUND_FUNCTION_TYPE",
1091: "JS_FUNCTION_TYPE",
}
# List of known V8 maps.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment