Skip to content

Commit

Permalink
[intl] Port CanonicalizeLocaleList to C++
Browse files Browse the repository at this point in the history
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/1161545
Reviewed-by: Sathya Gunasekaran <gsathya@chromium.org>
Commit-Queue: Jakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/master@{#54952}
  • Loading branch information
jakobkummerow authored and Commit Bot committed Aug 7, 2018
1 parent 38c664f commit bbe8db5
Show file tree
Hide file tree
Showing 13 changed files with 201 additions and 174 deletions.
2 changes: 1 addition & 1 deletion src/builtins/builtins-array.cc
Expand Up @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion src/builtins/builtins-intl.cc
Expand Up @@ -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) {
Expand Down
1 change: 0 additions & 1 deletion src/contexts.h
Expand Up @@ -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) \
Expand Down
55 changes: 25 additions & 30 deletions src/intl.cc
Expand Up @@ -155,26 +155,25 @@ 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;
UErrorCode status;
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();
Expand All @@ -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());
Expand Down Expand Up @@ -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, "");
Expand All @@ -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 =
Expand All @@ -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 =
Expand All @@ -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);
}
}
Expand All @@ -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()) {
Expand All @@ -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);
}

Expand Down
20 changes: 8 additions & 12 deletions src/intl.h
Expand Up @@ -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();

Expand Down
7 changes: 0 additions & 7 deletions src/js/intl.js
Expand Up @@ -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,
Expand Down
8 changes: 6 additions & 2 deletions src/json-stringifier.cc
Expand Up @@ -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++) {
Expand Down Expand Up @@ -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
Expand Down
6 changes: 3 additions & 3 deletions src/objects.cc
Expand Up @@ -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);
}

Expand Down
2 changes: 1 addition & 1 deletion src/objects.h
Expand Up @@ -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);
Expand Down

0 comments on commit bbe8db5

Please sign in to comment.