Commit bbe8db59 authored by Jakob Kummerow's avatar Jakob Kummerow Committed by Commit Bot

[intl] Port CanonicalizeLocaleList to C++

This CL also contains some drive-by cleanup of related code.

Bug: v8:5751, v8:7987
Cq-Include-Trybots: luci.v8.try:v8_linux_noi18n_rel_ng
Change-Id: I6144d16c1d85922efc1dc419cce8a2eba2a60056
Reviewed-on: https://chromium-review.googlesource.com/1161545Reviewed-by: 's avatarSathya Gunasekaran <gsathya@chromium.org>
Commit-Queue: Jakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/master@{#54952}
parent 38c664fa
......@@ -316,7 +316,7 @@ V8_WARN_UNUSED_RESULT Object* GenericArrayPush(Isolate* isolate,
Handle<Object> raw_length_number;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, raw_length_number,
Object::GetLengthFromArrayLike(isolate, Handle<Object>::cast(receiver)));
Object::GetLengthFromArrayLike(isolate, receiver));
// 3. Let args be a List whose elements are, in left to right order,
// the arguments that were passed to this function invocation.
......
......@@ -41,7 +41,7 @@ BUILTIN(StringPrototypeToUpperCaseIntl) {
HandleScope scope(isolate);
TO_THIS_STRING(string, "String.prototype.toUpperCase");
string = String::Flatten(isolate, string);
return ConvertCase(string, true, isolate);
RETURN_RESULT_OR_FAILURE(isolate, ConvertCase(string, true, isolate));
}
BUILTIN(StringPrototypeNormalizeIntl) {
......
......@@ -90,7 +90,6 @@ enum ContextLookupFlags {
V(MAP_HAS_INDEX, JSFunction, map_has) \
V(MAP_SET_INDEX, JSFunction, map_set) \
V(FUNCTION_HAS_INSTANCE_INDEX, JSFunction, function_has_instance) \
V(INITIALIZE_LOCALE_LIST_FUNCTION_INDEX, JSFunction, initialize_locale_list) \
V(OBJECT_VALUE_OF, JSFunction, object_value_of) \
V(OBJECT_TO_STRING, JSFunction, object_to_string) \
V(PROMISE_CATCH_INDEX, JSFunction, promise_catch) \
......
......@@ -155,10 +155,8 @@ const UChar* GetUCharBufferFromFlat(const String::FlatContent& flat,
}
}
V8_WARN_UNUSED_RESULT Object* LocaleConvertCase(Handle<String> s,
Isolate* isolate,
bool is_to_upper,
const char* lang) {
MaybeHandle<String> LocaleConvertCase(Handle<String> s, Isolate* isolate,
bool is_to_upper, const char* lang) {
auto case_converter = is_to_upper ? u_strToUpper : u_strToLower;
int32_t src_length = s->length();
int32_t dest_length = src_length;
......@@ -166,15 +164,16 @@ V8_WARN_UNUSED_RESULT Object* LocaleConvertCase(Handle<String> s,
Handle<SeqTwoByteString> result;
std::unique_ptr<uc16[]> sap;
if (dest_length == 0) return ReadOnlyRoots(isolate).empty_string();
if (dest_length == 0) return ReadOnlyRoots(isolate).empty_string_handle();
// This is not a real loop. It'll be executed only once (no overflow) or
// twice (overflow).
for (int i = 0; i < 2; ++i) {
// Case conversion can increase the string length (e.g. sharp-S => SS) so
// that we have to handle RangeError exceptions here.
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, result, isolate->factory()->NewRawTwoByteString(dest_length));
ASSIGN_RETURN_ON_EXCEPTION(
isolate, result, isolate->factory()->NewRawTwoByteString(dest_length),
String);
DisallowHeapAllocation no_gc;
DCHECK(s->IsFlat());
String::FlatContent flat = s->GetFlatContent();
......@@ -192,21 +191,17 @@ V8_WARN_UNUSED_RESULT Object* LocaleConvertCase(Handle<String> s,
DCHECK(U_SUCCESS(status));
if (V8_LIKELY(status == U_STRING_NOT_TERMINATED_WARNING)) {
DCHECK(dest_length == result->length());
return *result;
return result;
}
if (U_SUCCESS(status)) {
DCHECK(dest_length < result->length());
return *Handle<SeqTwoByteString>::cast(
SeqString::Truncate(result, dest_length));
}
return *s;
DCHECK(dest_length < result->length());
return SeqString::Truncate(result, dest_length);
}
// A stripped-down version of ConvertToLower that can only handle flat one-byte
// strings and does not allocate. Note that {src} could still be, e.g., a
// one-byte sliced string with a two-byte parent string.
// Called from TF builtins.
V8_WARN_UNUSED_RESULT Object* ConvertOneByteToLower(String* src, String* dst) {
V8_WARN_UNUSED_RESULT String* ConvertOneByteToLower(String* src, String* dst) {
DCHECK_EQ(src->length(), dst->length());
DCHECK(src->HasOnlyOneByteChars());
DCHECK(src->IsFlat());
......@@ -251,8 +246,7 @@ V8_WARN_UNUSED_RESULT Object* ConvertOneByteToLower(String* src, String* dst) {
return dst;
}
V8_WARN_UNUSED_RESULT Object* ConvertToLower(Handle<String> s,
Isolate* isolate) {
MaybeHandle<String> ConvertToLower(Handle<String> s, Isolate* isolate) {
if (!s->HasOnlyOneByteChars()) {
// Use a slower implementation for strings with characters beyond U+00FF.
return LocaleConvertCase(s, isolate, false, "");
......@@ -274,17 +268,16 @@ V8_WARN_UNUSED_RESULT Object* ConvertToLower(Handle<String> s,
bool is_short = length < static_cast<int>(sizeof(uintptr_t));
if (is_short) {
bool is_lower_ascii = FindFirstUpperOrNonAscii(*s, length) == length;
if (is_lower_ascii) return *s;
if (is_lower_ascii) return s;
}
Handle<SeqOneByteString> result =
isolate->factory()->NewRawOneByteString(length).ToHandleChecked();
return ConvertOneByteToLower(*s, *result);
return Handle<String>(ConvertOneByteToLower(*s, *result), isolate);
}
V8_WARN_UNUSED_RESULT Object* ConvertToUpper(Handle<String> s,
Isolate* isolate) {
MaybeHandle<String> ConvertToUpper(Handle<String> s, Isolate* isolate) {
int32_t length = s->length();
if (s->HasOnlyOneByteChars() && length > 0) {
Handle<SeqOneByteString> result =
......@@ -304,8 +297,9 @@ V8_WARN_UNUSED_RESULT Object* ConvertToUpper(Handle<String> s,
FastAsciiConvert<false>(reinterpret_cast<char*>(result->GetChars()),
reinterpret_cast<const char*>(src.start()),
length, &has_changed_character);
if (index_to_first_unprocessed == length)
return has_changed_character ? *result : *s;
if (index_to_first_unprocessed == length) {
return has_changed_character ? result : s;
}
// If not ASCII, we keep the result up to index_to_first_unprocessed and
// process the rest.
is_result_single_byte =
......@@ -314,7 +308,7 @@ V8_WARN_UNUSED_RESULT Object* ConvertToUpper(Handle<String> s,
} else {
DCHECK(flat.IsTwoByte());
Vector<const uint16_t> src = flat.ToUC16Vector();
if (ToUpperFastASCII(src, result)) return *result;
if (ToUpperFastASCII(src, result)) return result;
is_result_single_byte = ToUpperOneByte(src, dest, &sharp_s_count);
}
}
......@@ -325,13 +319,14 @@ V8_WARN_UNUSED_RESULT Object* ConvertToUpper(Handle<String> s,
return LocaleConvertCase(s, isolate, true, "");
}
if (sharp_s_count == 0) return *result;
if (sharp_s_count == 0) return result;
// We have sharp_s_count sharp-s characters, but the result is still
// in the Latin-1 range.
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
ASSIGN_RETURN_ON_EXCEPTION(
isolate, result,
isolate->factory()->NewRawOneByteString(length + sharp_s_count));
isolate->factory()->NewRawOneByteString(length + sharp_s_count),
String);
DisallowHeapAllocation no_gc;
String::FlatContent flat = s->GetFlatContent();
if (flat.IsOneByte()) {
......@@ -340,14 +335,14 @@ V8_WARN_UNUSED_RESULT Object* ConvertToUpper(Handle<String> s,
ToUpperWithSharpS(flat.ToUC16Vector(), result);
}
return *result;
return result;
}
return LocaleConvertCase(s, isolate, true, "");
}
V8_WARN_UNUSED_RESULT Object* ConvertCase(Handle<String> s, bool is_upper,
Isolate* isolate) {
MaybeHandle<String> ConvertCase(Handle<String> s, bool is_upper,
Isolate* isolate) {
return is_upper ? ConvertToUpper(s, isolate) : ConvertToLower(s, isolate);
}
......
......@@ -37,18 +37,14 @@ enum class IcuService {
const UChar* GetUCharBufferFromFlat(const String::FlatContent& flat,
std::unique_ptr<uc16[]>* dest,
int32_t length);
V8_WARN_UNUSED_RESULT Object* LocaleConvertCase(Handle<String> s,
Isolate* isolate,
bool is_to_upper,
const char* lang);
V8_WARN_UNUSED_RESULT Object* ConvertToLower(Handle<String> s,
Isolate* isolate);
V8_WARN_UNUSED_RESULT Object* ConvertToUpper(Handle<String> s,
Isolate* isolate);
V8_WARN_UNUSED_RESULT Object* ConvertCase(Handle<String> s, bool is_upper,
Isolate* isolate);
V8_WARN_UNUSED_RESULT Object* ConvertOneByteToLower(String* src, String* dst);
MaybeHandle<String> LocaleConvertCase(Handle<String> s, Isolate* isolate,
bool is_to_upper, const char* lang);
MaybeHandle<String> ConvertToLower(Handle<String> s, Isolate* isolate);
MaybeHandle<String> ConvertToUpper(Handle<String> s, Isolate* isolate);
MaybeHandle<String> ConvertCase(Handle<String> s, bool is_upper,
Isolate* isolate);
V8_WARN_UNUSED_RESULT String* ConvertOneByteToLower(String* src, String* dst);
const uint8_t* ToLatin1LowerTable();
......
......@@ -772,13 +772,6 @@ function initializeLocaleList(locales) {
return freezeArray(canonicalizeLocaleList(locales));
}
// TODO(ftang): remove the %InstallToContext once
// initializeLocaleList is available in C++
// https://bugs.chromium.org/p/v8/issues/detail?id=7987
%InstallToContext([
"initialize_locale_list", initializeLocaleList
]);
// ECMA 402 section 8.2.1
DEFINE_METHOD(
GlobalIntl,
......
......@@ -226,7 +226,9 @@ bool JsonStringifier::InitializeReplacer(Handle<Object> replacer) {
Handle<Object> length_obj;
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate_, length_obj,
Object::GetLengthFromArrayLike(isolate_, replacer), false);
Object::GetLengthFromArrayLike(isolate_,
Handle<JSReceiver>::cast(replacer)),
false);
uint32_t length;
if (!length_obj->ToUint32(&length)) length = kMaxUInt32;
for (uint32_t i = 0; i < length; i++) {
......@@ -720,7 +722,9 @@ JsonStringifier::Result JsonStringifier::SerializeJSProxy(
Handle<Object> length_object;
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate_, length_object,
Object::GetLengthFromArrayLike(isolate_, object), EXCEPTION);
Object::GetLengthFromArrayLike(isolate_,
Handle<JSReceiver>::cast(object)),
EXCEPTION);
uint32_t length;
if (!length_object->ToUint32(&length)) {
// Technically, we need to be able to handle lengths outside the
......
......@@ -953,11 +953,11 @@ MaybeHandle<FixedArray> Object::CreateListFromArrayLike(
// static
MaybeHandle<Object> Object::GetLengthFromArrayLike(Isolate* isolate,
Handle<Object> object) {
Handle<JSReceiver> object) {
Handle<Object> val;
Handle<Object> key = isolate->factory()->length_string();
Handle<Name> key = isolate->factory()->length_string();
ASSIGN_RETURN_ON_EXCEPTION(
isolate, val, Runtime::GetObjectProperty(isolate, object, key), Object);
isolate, val, JSReceiver::GetProperty(isolate, object, key), Object);
return Object::ToLength(isolate, val);
}
......
......@@ -1289,7 +1289,7 @@ class Object {
// Get length property and apply ToLength.
V8_WARN_UNUSED_RESULT static MaybeHandle<Object> GetLengthFromArrayLike(
Isolate* isolate, Handle<Object> object);
Isolate* isolate, Handle<JSReceiver> object);
// ES6 section 12.5.6 The typeof Operator
static Handle<String> TypeOf(Isolate* isolate, Handle<Object> object);
......
This diff is collapsed.
......@@ -195,7 +195,7 @@ class Intl {
static V8_WARN_UNUSED_RESULT MaybeHandle<JSObject> AvailableLocalesOf(
Isolate* isolate, Handle<String> service);
static V8_WARN_UNUSED_RESULT Handle<String> DefaultLocale(Isolate* isolate);
static std::string DefaultLocale(Isolate* isolate);
static void DefineWEProperty(Isolate* isolate, Handle<JSObject> target,
Handle<Name> key, Handle<Object> value);
......@@ -234,9 +234,12 @@ class Intl {
// This currently calls out to the JavaScript implementation of
// CanonicalizeLocaleList.
// Note: This is deprecated glue code, required only as long as ResolveLocale
// still calls a JS implementation. The C++ successor is the overloaded
// version below that returns a Maybe<std::vector<std::string>>.
//
// ecma402/#sec-canonicalizelocalelist
V8_WARN_UNUSED_RESULT static MaybeHandle<JSObject> CanonicalizeLocaleList(
V8_WARN_UNUSED_RESULT static MaybeHandle<JSObject> CanonicalizeLocaleListJS(
Isolate* isolate, Handle<Object> locales);
// ECMA402 9.2.10. GetOption( options, property, type, values, fallback)
......@@ -275,9 +278,18 @@ class Intl {
Isolate* isolate, Handle<JSReceiver> options, const char* property,
const char* service, bool* result);
// Canonicalize the localeID.
static MaybeHandle<String> CanonicalizeLanguageTag(Isolate* isolate,
Handle<Object> localeID);
// Canonicalize the locale.
// https://tc39.github.io/ecma402/#sec-canonicalizelanguagetag,
// including type check and structural validity check.
static Maybe<std::string> CanonicalizeLanguageTag(Isolate* isolate,
Handle<Object> locale_in);
// https://tc39.github.io/ecma402/#sec-canonicalizelocalelist
// {only_return_one_result} is an optimization for callers that only
// care about the first result.
static Maybe<std::vector<std::string>> CanonicalizeLocaleList(
Isolate* isolate, Handle<Object> locales,
bool only_return_one_result = false);
// ecma-402/#sec-currencydigits
// The currency is expected to an all upper case string value.
......
......@@ -89,9 +89,11 @@ MaybeHandle<JSPluralRules> JSPluralRules::InitializePluralRules(
Isolate* isolate, Handle<JSPluralRules> plural_rules,
Handle<Object> locales, Handle<Object> options_obj) {
// 1. Let requestedLocales be ? CanonicalizeLocaleList(locales).
// TODO(jkummerow): Port ResolveLocale, then use the C++ version of
// CanonicalizeLocaleList here.
Handle<JSObject> requested_locales;
ASSIGN_RETURN_ON_EXCEPTION(isolate, requested_locales,
Intl::CanonicalizeLocaleList(isolate, locales),
Intl::CanonicalizeLocaleListJS(isolate, locales),
JSPluralRules);
// 2. If options is undefined, then
......
......@@ -94,8 +94,11 @@ RUNTIME_FUNCTION(Runtime_CanonicalizeLanguageTag) {
DCHECK_EQ(1, args.length());
CONVERT_ARG_HANDLE_CHECKED(Object, locale, 0);
RETURN_RESULT_OR_FAILURE(isolate,
Intl::CanonicalizeLanguageTag(isolate, locale));
std::string canonicalized;
if (!Intl::CanonicalizeLanguageTag(isolate, locale).To(&canonicalized)) {
return ReadOnlyRoots(isolate).exception();
}
return *isolate->factory()->NewStringFromAsciiChecked(canonicalized.c_str());
}
RUNTIME_FUNCTION(Runtime_AvailableLocalesOf) {
......@@ -112,7 +115,8 @@ RUNTIME_FUNCTION(Runtime_GetDefaultICULocale) {
HandleScope scope(isolate);
DCHECK_EQ(0, args.length());
return *Intl::DefaultLocale(isolate);
return *isolate->factory()->NewStringFromAsciiChecked(
Intl::DefaultLocale(isolate).c_str());
}
RUNTIME_FUNCTION(Runtime_IsWellFormedCurrencyCode) {
......@@ -476,7 +480,7 @@ RUNTIME_FUNCTION(Runtime_StringToLowerCaseIntl) {
DCHECK_EQ(args.length(), 1);
CONVERT_ARG_HANDLE_CHECKED(String, s, 0);
s = String::Flatten(isolate, s);
return ConvertToLower(s, isolate);
RETURN_RESULT_OR_FAILURE(isolate, ConvertToLower(s, isolate));
}
RUNTIME_FUNCTION(Runtime_StringToUpperCaseIntl) {
......@@ -484,7 +488,7 @@ RUNTIME_FUNCTION(Runtime_StringToUpperCaseIntl) {
DCHECK_EQ(args.length(), 1);
CONVERT_ARG_HANDLE_CHECKED(String, s, 0);
s = String::Flatten(isolate, s);
return ConvertToUpper(s, isolate);
RETURN_RESULT_OR_FAILURE(isolate, ConvertToUpper(s, isolate));
}
RUNTIME_FUNCTION(Runtime_DateCacheVersion) {
......
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