From 13969b6bd459bd68eef444a8a107c830e81095f7 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sun, 21 Jun 2026 19:02:35 +0200 Subject: [PATCH] LibJS: Store primitive strings as UTF-16 Keep primitive string storage in Utf16String and remove the UTF-8 storage path from PrimitiveString. ASCII strings still use compact Utf16String ASCII storage, while UTF-16 becomes the only owned representation. --- Libraries/LibJS/Bytecode/Executable.cpp | 2 +- .../LibJS/Runtime/AbstractOperations.cpp | 5 +- Libraries/LibJS/Runtime/DateConstructor.cpp | 2 +- Libraries/LibJS/Runtime/DatePrototype.cpp | 2 +- Libraries/LibJS/Runtime/GlobalObject.cpp | 6 +- .../LibJS/Runtime/Intl/AbstractOperations.cpp | 4 +- .../Runtime/Intl/CollatorConstructor.cpp | 4 +- .../Intl/DateTimeFormatConstructor.cpp | 6 +- .../Runtime/Intl/DisplayNamesConstructor.cpp | 8 +- .../Runtime/Intl/DisplayNamesPrototype.cpp | 4 +- .../LibJS/Runtime/Intl/DurationFormat.cpp | 2 +- .../Intl/DurationFormatConstructor.cpp | 2 +- .../Runtime/Intl/ListFormatConstructor.cpp | 4 +- .../LibJS/Runtime/Intl/LocaleConstructor.cpp | 2 +- .../Runtime/Intl/NumberFormatConstructor.cpp | 24 +-- .../Runtime/Intl/PluralRulesConstructor.cpp | 6 +- .../Intl/RelativeTimeFormatConstructor.cpp | 4 +- .../Runtime/Intl/SegmenterConstructor.cpp | 2 +- .../LibJS/Runtime/IteratorConstructor.cpp | 2 +- Libraries/LibJS/Runtime/ObjectPrototype.cpp | 7 +- Libraries/LibJS/Runtime/PrimitiveString.cpp | 196 ++---------------- Libraries/LibJS/Runtime/PrimitiveString.h | 16 +- .../Runtime/Temporal/AbstractOperations.cpp | 18 +- Libraries/LibJS/Runtime/Temporal/Calendar.cpp | 2 +- Libraries/LibJS/Runtime/Temporal/Duration.cpp | 2 +- Libraries/LibJS/Runtime/Temporal/Instant.cpp | 2 +- .../LibJS/Runtime/Temporal/PlainDate.cpp | 2 +- .../Runtime/Temporal/PlainDateConstructor.cpp | 2 +- .../LibJS/Runtime/Temporal/PlainDateTime.cpp | 2 +- .../Temporal/PlainDateTimeConstructor.cpp | 2 +- .../LibJS/Runtime/Temporal/PlainMonthDay.cpp | 2 +- .../Temporal/PlainMonthDayConstructor.cpp | 2 +- .../LibJS/Runtime/Temporal/PlainTime.cpp | 2 +- .../LibJS/Runtime/Temporal/PlainYearMonth.cpp | 2 +- .../Temporal/PlainYearMonthConstructor.cpp | 2 +- Libraries/LibJS/Runtime/Temporal/TimeZone.cpp | 2 +- .../LibJS/Runtime/Temporal/ZonedDateTime.cpp | 2 +- .../Temporal/ZonedDateTimeConstructor.cpp | 2 +- Libraries/LibJS/Runtime/Uint8Array.cpp | 18 +- Libraries/LibJS/Runtime/VM.cpp | 20 +- Libraries/LibJS/Runtime/VM.h | 6 - Libraries/LibJS/Runtime/Value.cpp | 10 +- Libraries/LibJS/RustIntegration.cpp | 2 +- Libraries/LibWeb/DOMURL/Origin.cpp | 2 +- Libraries/LibWeb/HTML/Scripting/ImportMap.cpp | 2 +- Libraries/LibWeb/HTML/StructuredSerialize.cpp | 2 +- .../LibWeb/Streams/AbstractOperations.cpp | 4 +- Tests/LibJS/test-js.cpp | 4 +- Tests/LibJS/test-primitive-string.cpp | 25 ++- 49 files changed, 136 insertions(+), 317 deletions(-) diff --git a/Libraries/LibJS/Bytecode/Executable.cpp b/Libraries/LibJS/Bytecode/Executable.cpp index b408075834..fa509acc4a 100644 --- a/Libraries/LibJS/Bytecode/Executable.cpp +++ b/Libraries/LibJS/Bytecode/Executable.cpp @@ -411,7 +411,7 @@ static void dump_metadata(StringBuilder& output, Executable const& executable) else if (value.is_bigint()) output.appendff("BigInt({})", MUST(value.as_bigint().to_string())); else if (value.is_string()) - output.appendff("String(\"{}\")", value.as_string().utf8_string_view()); + output.appendff("String(\"{}\")", value.as_string().utf16_string_view()); else if (value.is_undefined()) output.append("Undefined"sv); else if (value.is_null()) diff --git a/Libraries/LibJS/Runtime/AbstractOperations.cpp b/Libraries/LibJS/Runtime/AbstractOperations.cpp index b9c9322ab0..5e12e382de 100644 --- a/Libraries/LibJS/Runtime/AbstractOperations.cpp +++ b/Libraries/LibJS/Runtime/AbstractOperations.cpp @@ -646,7 +646,8 @@ ThrowCompletionOr perform_eval(VM& vm, Value x, CallerMode strict_caller, // 6. NOTE: In the case of a direct eval, evalRealm is the realm of both the caller of eval and of the eval function itself. // 7. Perform ? HostEnsureCanCompileStrings(evalRealm, « », xStr, xStr, direct, « », x). - TRY(vm.host_ensure_can_compile_strings(eval_realm, {}, code_string->utf8_string_view(), code_string->utf8_string_view(), direct == EvalMode::Direct ? CompilationType::DirectEval : CompilationType::IndirectEval, {}, x)); + auto code_string_utf8 = code_string->utf8_string(); + TRY(vm.host_ensure_can_compile_strings(eval_realm, {}, code_string_utf8, code_string_utf8, direct == EvalMode::Direct ? CompilationType::DirectEval : CompilationType::IndirectEval, {}, x)); // 8. Let inFunction be false. bool in_function = false; @@ -1978,7 +1979,7 @@ ThrowCompletionOr get_rounding_mode_option(VM& vm, Object const& o auto string_value = TRY(get_option(vm, options, vm.names.roundingMode, OptionType::String, allowed_strings, string_fallback)); // 4. Return the value from the "Rounding Mode" column of the row with stringValue in its "String Identifier" column. - return static_cast(allowed_strings.first_index_of(string_value.as_string().utf8_string_view()).value()); + return static_cast(allowed_strings.first_index_of(string_value.as_string().utf8_string()).value()); } // 14.5.2.4 GetRoundingIncrementOption ( options ), https://tc39.es/proposal-temporal/#sec-temporal-getroundingincrementoption diff --git a/Libraries/LibJS/Runtime/DateConstructor.cpp b/Libraries/LibJS/Runtime/DateConstructor.cpp index cbcffa5179..901fe7bf8d 100644 --- a/Libraries/LibJS/Runtime/DateConstructor.cpp +++ b/Libraries/LibJS/Runtime/DateConstructor.cpp @@ -97,7 +97,7 @@ ThrowCompletionOr> DateConstructor::construct(FunctionObject& ne if (primitive.is_string()) { // 1. Assert: The next step never returns an abrupt completion because Type(v) is String. // 2. Let tv be the result of parsing v as a date, in exactly the same manner as for the parse method (21.4.3.2). - time_value = parse_date_string(vm, primitive.as_string().utf8_string_view()); + time_value = parse_date_string(vm, primitive.as_string().utf8_string()); } // iii. Else, else { diff --git a/Libraries/LibJS/Runtime/DatePrototype.cpp b/Libraries/LibJS/Runtime/DatePrototype.cpp index a28d0262ee..9b5dee5f8f 100644 --- a/Libraries/LibJS/Runtime/DatePrototype.cpp +++ b/Libraries/LibJS/Runtime/DatePrototype.cpp @@ -1212,7 +1212,7 @@ JS_DEFINE_NATIVE_FUNCTION(DatePrototype::symbol_to_primitive) auto hint_value = vm.argument(0); if (!hint_value.is_string()) return vm.throw_completion(ErrorType::InvalidHint, hint_value); - auto hint = hint_value.as_string().utf8_string_view(); + auto hint = hint_value.as_string().utf16_string_view(); Value::PreferredType try_first; if (hint == "string"sv || hint == "default"sv) try_first = Value::PreferredType::String; diff --git a/Libraries/LibJS/Runtime/GlobalObject.cpp b/Libraries/LibJS/Runtime/GlobalObject.cpp index 907995ac0c..30eec103d1 100644 --- a/Libraries/LibJS/Runtime/GlobalObject.cpp +++ b/Libraries/LibJS/Runtime/GlobalObject.cpp @@ -591,7 +591,7 @@ JS_DEFINE_NATIVE_FUNCTION(GlobalObject::unescape) auto string = TRY(vm.argument(0).to_utf16_string(vm)); // 2. Let length be the length of string. - ssize_t length = string.length_in_code_units(); + size_t length = string.length_in_code_units(); // 3. Let R be the empty String. Utf16StringBuilder unescaped(length); @@ -607,7 +607,7 @@ JS_DEFINE_NATIVE_FUNCTION(GlobalObject::unescape) // i. Let hexEscape be the empty String. // ii. Let skip be 0. // iii. If k ≤ length - 6 and the code unit at index k + 1 within string is the code unit 0x0075 (LATIN SMALL LETTER U), then - if (k <= length - 6 + if (k + 5 < length && string.code_unit_at(k + 1) == 'u' && is_ascii_hex_digit(string.code_unit_at(k + 2)) && is_ascii_hex_digit(string.code_unit_at(k + 3)) @@ -620,7 +620,7 @@ JS_DEFINE_NATIVE_FUNCTION(GlobalObject::unescape) k += 5; } // iv. Else if k ≤ length - 3, then - else if (k <= length - 3 + else if (k + 2 < length && is_ascii_hex_digit(string.code_unit_at(k + 1)) && is_ascii_hex_digit(string.code_unit_at(k + 2))) { // 1. Set hexEscape to the substring of string from k + 1 to k + 3. diff --git a/Libraries/LibJS/Runtime/Intl/AbstractOperations.cpp b/Libraries/LibJS/Runtime/Intl/AbstractOperations.cpp index a20bcbe471..2ddded130e 100644 --- a/Libraries/LibJS/Runtime/Intl/AbstractOperations.cpp +++ b/Libraries/LibJS/Runtime/Intl/AbstractOperations.cpp @@ -451,7 +451,7 @@ ResolvedLocale resolve_locale(ReadonlySpan requested_locales, LocaleOpti Optional matcher_result; // 2. If matcher is "lookup", then - if (matcher.is_string() && matcher.as_string().utf8_string_view() == "lookup"sv) { + if (matcher.is_string() && matcher.as_string().utf8_string() == "lookup"sv) { // a. Let r be LookupMatchingLocaleByPrefix(availableLocales, requestedLocales). matcher_result = lookup_matching_locale_by_prefix(requested_locales); } @@ -688,7 +688,7 @@ ThrowCompletionOr> filter_locales(VM& vm, ReadonlySpan re Optional match; // a. If matcher is "lookup", then - if (matcher.as_string().utf8_string_view() == "lookup"sv) { + if (matcher.as_string().utf8_string() == "lookup"sv) { // i. Let match be LookupMatchingLocaleByPrefix(availableLocales, « locale »). match = lookup_matching_locale_by_prefix({ { locale } }); } diff --git a/Libraries/LibJS/Runtime/Intl/CollatorConstructor.cpp b/Libraries/LibJS/Runtime/Intl/CollatorConstructor.cpp index 4e2c1ed07a..9e5f217ff0 100644 --- a/Libraries/LibJS/Runtime/Intl/CollatorConstructor.cpp +++ b/Libraries/LibJS/Runtime/Intl/CollatorConstructor.cpp @@ -69,7 +69,7 @@ ThrowCompletionOr> CollatorConstructor::construct(FunctionObject auto usage = TRY(get_option(vm, options, vm.names.usage, OptionType::String, { "sort"sv, "search"sv }, "sort"sv)); // 8. Set collator.[[Usage]] to usage. - collator->set_usage(usage.as_string().utf8_string_view()); + collator->set_usage(usage.as_string().utf8_string()); // 9. If usage is "sort", then // a. Let localeData be %Intl.Collator%.[[SortLocaleData]]. @@ -113,7 +113,7 @@ ThrowCompletionOr> CollatorConstructor::construct(FunctionObject Optional sensitivity; if (!sensitivity_value.is_undefined()) - sensitivity = Unicode::sensitivity_from_string(sensitivity_value.as_string().utf8_string_view()); + sensitivity = Unicode::sensitivity_from_string(sensitivity_value.as_string().utf8_string()); // 21. Let defaultIgnorePunctuation be resolvedLocaleData.[[ignorePunctuation]]. // NOTE: We do not acquire resolvedLocaleData.[[ignorePunctuation]] here. Instead, we let LibUnicode fill in the diff --git a/Libraries/LibJS/Runtime/Intl/DateTimeFormatConstructor.cpp b/Libraries/LibJS/Runtime/Intl/DateTimeFormatConstructor.cpp index 39c68cdb7a..3f72a29e99 100644 --- a/Libraries/LibJS/Runtime/Intl/DateTimeFormatConstructor.cpp +++ b/Libraries/LibJS/Runtime/Intl/DateTimeFormatConstructor.cpp @@ -275,7 +275,7 @@ ThrowCompletionOr> create_date_time_format(VM& vm, Funct // d. Set formatOptions.[[]] to value. if (!value.is_undefined()) { - option = Unicode::calendar_pattern_style_from_string(value.as_string().utf8_string_view()); + option = Unicode::calendar_pattern_style_from_string(value.as_string().utf8_string()); // e. If value is not undefined, then // i. Set hasExplicitFormatComponents to true. @@ -294,14 +294,14 @@ ThrowCompletionOr> create_date_time_format(VM& vm, Funct // 29. Set dateTimeFormat.[[DateStyle]] to dateStyle. if (!date_style.is_undefined()) - date_time_format->set_date_style(date_style.as_string().utf8_string_view()); + date_time_format->set_date_style(date_style.as_string().utf8_string()); // 30. Let timeStyle be ? GetOption(options, "timeStyle", string, « "full", "long", "medium", "short" », undefined). auto time_style = TRY(get_option(vm, *options, vm.names.timeStyle, OptionType::String, AK::Array { "full"sv, "long"sv, "medium"sv, "short"sv }, Empty {})); // 31. Set dateTimeFormat.[[TimeStyle]] to timeStyle. if (!time_style.is_undefined()) - date_time_format->set_time_style(time_style.as_string().utf8_string_view()); + date_time_format->set_time_style(time_style.as_string().utf8_string()); // 32. Let formats be resolvedLocaleData.[[formats]].[[]]. diff --git a/Libraries/LibJS/Runtime/Intl/DisplayNamesConstructor.cpp b/Libraries/LibJS/Runtime/Intl/DisplayNamesConstructor.cpp index 726e237ff6..b4309085cf 100644 --- a/Libraries/LibJS/Runtime/Intl/DisplayNamesConstructor.cpp +++ b/Libraries/LibJS/Runtime/Intl/DisplayNamesConstructor.cpp @@ -64,7 +64,7 @@ ThrowCompletionOr> DisplayNamesConstructor::construct(FunctionOb auto style = TRY(get_option(vm, *options, vm.names.style, OptionType::String, { "narrow"sv, "short"sv, "long"sv }, "long"sv)); // 7. Set displayNames.[[Style]] to style. - display_names->set_style(style.as_string().utf8_string_view()); + display_names->set_style(style.as_string().utf8_string()); // 8. Let type be ? GetOption(options, "type", string, « "language", "region", "script", "currency", "calendar", "dateTimeField" », undefined). auto type = TRY(get_option(vm, *options, vm.names.type, OptionType::String, { "language"sv, "region"sv, "script"sv, "currency"sv, "calendar"sv, "dateTimeField"sv }, Empty {})); @@ -74,13 +74,13 @@ ThrowCompletionOr> DisplayNamesConstructor::construct(FunctionOb return vm.throw_completion(ErrorType::IsUndefined, "options.type"sv); // 10. Set displayNames.[[Type]] to type. - display_names->set_type(type.as_string().utf8_string_view()); + display_names->set_type(type.as_string().utf8_string()); // 11. Let fallback be ? GetOption(options, "fallback", string, « "code", "none" », "code"). auto fallback = TRY(get_option(vm, *options, vm.names.fallback, OptionType::String, { "code"sv, "none"sv }, "code"sv)); // 12. Set displayNames.[[Fallback]] to fallback. - display_names->set_fallback(fallback.as_string().utf8_string_view()); + display_names->set_fallback(fallback.as_string().utf8_string()); // 13. Set displayNames.[[Locale]] to r.[[Locale]]. display_names->set_locale(move(result.locale)); @@ -98,7 +98,7 @@ ThrowCompletionOr> DisplayNamesConstructor::construct(FunctionOb // 20. If type is "language", then if (display_names->type() == DisplayNames::Type::Language) { // a. Set displayNames.[[LanguageDisplay]] to languageDisplay. - display_names->set_language_display(language_display.as_string().utf8_string_view()); + display_names->set_language_display(language_display.as_string().utf8_string()); // b. Set typeFields to typeFields.[[]]. // c. Assert: typeFields is a Record (see 12.2.3). diff --git a/Libraries/LibJS/Runtime/Intl/DisplayNamesPrototype.cpp b/Libraries/LibJS/Runtime/Intl/DisplayNamesPrototype.cpp index 490769eafa..a5e8dcf7fa 100644 --- a/Libraries/LibJS/Runtime/Intl/DisplayNamesPrototype.cpp +++ b/Libraries/LibJS/Runtime/Intl/DisplayNamesPrototype.cpp @@ -77,8 +77,8 @@ JS_DEFINE_NATIVE_FUNCTION(DisplayNamesPrototype::of) code = PrimitiveString::create(vm, TRY(code.to_string(vm))); // 4. Let code be ? CanonicalCodeForDisplayNames(displayNames.[[Type]], code). - code = TRY(canonical_code_for_display_names(vm, display_names->type(), code.as_string().utf8_string_view())); - auto code_string = code.as_string().utf8_string_view(); + code = TRY(canonical_code_for_display_names(vm, display_names->type(), code.as_string().utf8_string())); + auto code_string = code.as_string().utf8_string(); // 5. Let fields be displayNames.[[Fields]]. // 6. If fields has a field [[]], return fields.[[]]. diff --git a/Libraries/LibJS/Runtime/Intl/DurationFormat.cpp b/Libraries/LibJS/Runtime/Intl/DurationFormat.cpp index 1c7caedf2b..63587cb8e0 100644 --- a/Libraries/LibJS/Runtime/Intl/DurationFormat.cpp +++ b/Libraries/LibJS/Runtime/Intl/DurationFormat.cpp @@ -269,7 +269,7 @@ ThrowCompletionOr get_duration_unit_options display_default = "auto"sv; } } else { - style = DurationFormat::value_style_from_string(style_value.as_string().utf8_string_view()); + style = DurationFormat::value_style_from_string(style_value.as_string().utf8_string()); } // 4. If style is "numeric" and IsFractionalSecondUnitName(unit) is true, then diff --git a/Libraries/LibJS/Runtime/Intl/DurationFormatConstructor.cpp b/Libraries/LibJS/Runtime/Intl/DurationFormatConstructor.cpp index b1174b607e..5afe13e373 100644 --- a/Libraries/LibJS/Runtime/Intl/DurationFormatConstructor.cpp +++ b/Libraries/LibJS/Runtime/Intl/DurationFormatConstructor.cpp @@ -83,7 +83,7 @@ ThrowCompletionOr> DurationFormatConstructor::construct(Function auto style = TRY(get_option(vm, *options, vm.names.style, OptionType::String, { "long"sv, "short"sv, "narrow"sv, "digital"sv }, "short"sv)); // 13. Set durationFormat.[[Style]] to style. - duration_format->set_style(style.as_string().utf8_string_view()); + duration_format->set_style(style.as_string().utf8_string()); // 14. Let prevStyle be the empty String. Optional previous_style; diff --git a/Libraries/LibJS/Runtime/Intl/ListFormatConstructor.cpp b/Libraries/LibJS/Runtime/Intl/ListFormatConstructor.cpp index 5206d34c9b..1d229c934a 100644 --- a/Libraries/LibJS/Runtime/Intl/ListFormatConstructor.cpp +++ b/Libraries/LibJS/Runtime/Intl/ListFormatConstructor.cpp @@ -66,13 +66,13 @@ ThrowCompletionOr> ListFormatConstructor::construct(FunctionObje auto type = TRY(get_option(vm, *options, vm.names.type, OptionType::String, { "conjunction"sv, "disjunction"sv, "unit"sv }, "conjunction"sv)); // 8. Set listFormat.[[Type]] to type. - list_format->set_type(type.as_string().utf8_string_view()); + list_format->set_type(type.as_string().utf8_string()); // 9. Let style be ? GetOption(options, "style", string, « "long", "short", "narrow" », "long"). auto style = TRY(get_option(vm, *options, vm.names.style, OptionType::String, { "long"sv, "short"sv, "narrow"sv }, "long"sv)); // 10. Set listFormat.[[Style]] to style. - list_format->set_style(style.as_string().utf8_string_view()); + list_format->set_style(style.as_string().utf8_string()); // 11. Let resolvedLocaleData be r.[[LocaleData]]. // 12. Let dataLocaleTypes be resolvedLocaleData.[[]]. diff --git a/Libraries/LibJS/Runtime/Intl/LocaleConstructor.cpp b/Libraries/LibJS/Runtime/Intl/LocaleConstructor.cpp index e4ddf10416..cf6f0ec338 100644 --- a/Libraries/LibJS/Runtime/Intl/LocaleConstructor.cpp +++ b/Libraries/LibJS/Runtime/Intl/LocaleConstructor.cpp @@ -37,7 +37,7 @@ static ThrowCompletionOr> get_string_option(VM& vm, Object cons if (option.is_undefined()) return OptionalNone {}; - if (validator && !validator(option.as_string().utf8_string_view())) + if (validator && !validator(option.as_string().utf8_string())) return vm.throw_completion(ErrorType::OptionIsNotValidValue, option, property); return option.as_string().utf8_string(); diff --git a/Libraries/LibJS/Runtime/Intl/NumberFormatConstructor.cpp b/Libraries/LibJS/Runtime/Intl/NumberFormatConstructor.cpp index 194df2de50..4e8103106e 100644 --- a/Libraries/LibJS/Runtime/Intl/NumberFormatConstructor.cpp +++ b/Libraries/LibJS/Runtime/Intl/NumberFormatConstructor.cpp @@ -78,7 +78,7 @@ ThrowCompletionOr> NumberFormatConstructor::construct(FunctionOb auto notation = TRY(get_option(vm, *options, vm.names.notation, OptionType::String, { "standard"sv, "scientific"sv, "engineering"sv, "compact"sv }, "standard"sv)); // 12. Set numberFormat.[[Notation]] to notation. - number_format->set_notation(notation.as_string().utf8_string_view()); + number_format->set_notation(notation.as_string().utf8_string()); int default_min_fraction_digits = 0; int default_max_fraction_digits = 0; @@ -121,7 +121,7 @@ ThrowCompletionOr> NumberFormatConstructor::construct(FunctionOb // 18. If notation is "compact", then if (number_format->notation() == Unicode::Notation::Compact) { // a. Set numberFormat.[[CompactDisplay]] to compactDisplay. - number_format->set_compact_display(compact_display.as_string().utf8_string_view()); + number_format->set_compact_display(compact_display.as_string().utf8_string()); // b. Set defaultUseGrouping to "min2". default_use_grouping = "min2"sv; @@ -150,7 +150,7 @@ ThrowCompletionOr> NumberFormatConstructor::construct(FunctionOb auto sign_display = TRY(get_option(vm, *options, vm.names.signDisplay, OptionType::String, { "auto"sv, "never"sv, "always"sv, "exceptZero"sv, "negative"sv }, "auto"sv)); // 25. Set numberFormat.[[SignDisplay]] to signDisplay. - number_format->set_sign_display(sign_display.as_string().utf8_string_view()); + number_format->set_sign_display(sign_display.as_string().utf8_string()); // 26. If the implementation supports the normative optional constructor mode of 4.3 Note 1, then // a. Let this be the this value. @@ -202,7 +202,7 @@ ThrowCompletionOr set_number_format_digit_options(VM& vm, NumberFormatBase // 10. Let roundingPriority be ? GetOption(options, "roundingPriority", STRING, « "auto", "morePrecision", "lessPrecision" », "auto"). auto rounding_priority_option = TRY(get_option(vm, options, vm.names.roundingPriority, OptionType::String, { "auto"sv, "morePrecision"sv, "lessPrecision"sv }, "auto"sv)); - auto rounding_priority = rounding_priority_option.as_string().utf8_string_view(); + auto rounding_priority = rounding_priority_option.as_string().utf8_string(); // 11. Let trailingZeroDisplay be ? GetOption(options, "trailingZeroDisplay", STRING, « "auto", "stripIfInteger" », "auto"). auto trailing_zero_display = TRY(get_option(vm, options, vm.names.trailingZeroDisplay, OptionType::String, { "auto"sv, "stripIfInteger"sv }, "auto"sv)); @@ -217,10 +217,10 @@ ThrowCompletionOr set_number_format_digit_options(VM& vm, NumberFormatBase intl_object.set_rounding_increment(*rounding_increment); // 15. Set intlObj.[[RoundingMode]] to roundingMode. - intl_object.set_rounding_mode(rounding_mode.as_string().utf8_string_view()); + intl_object.set_rounding_mode(rounding_mode.as_string().utf8_string()); // 16. Set intlObj.[[TrailingZeroDisplay]] to trailingZeroDisplay. - intl_object.set_trailing_zero_display(trailing_zero_display.as_string().utf8_string_view()); + intl_object.set_trailing_zero_display(trailing_zero_display.as_string().utf8_string()); // 17. If mnsd is undefined and mxsd is undefined, let hasSd be false. Otherwise, let hasSd be true. bool has_significant_digits = !min_significant_digits.is_undefined() || !max_significant_digits.is_undefined(); @@ -379,7 +379,7 @@ ThrowCompletionOr set_number_format_unit_options(VM& vm, NumberFormat& int auto style = TRY(get_option(vm, options, vm.names.style, OptionType::String, { "decimal"sv, "percent"sv, "currency"sv, "unit"sv }, "decimal"sv)); // 2. Set intlObj.[[Style]] to style. - intl_object.set_style(style.as_string().utf8_string_view()); + intl_object.set_style(style.as_string().utf8_string()); // 3. Let currency be ? GetOption(options, "currency", STRING, EMPTY, undefined). auto currency = TRY(get_option(vm, options, vm.names.currency, OptionType::String, {}, Empty {})); @@ -392,7 +392,7 @@ ThrowCompletionOr set_number_format_unit_options(VM& vm, NumberFormat& int } // 5. Else, // a. If IsWellFormedCurrencyCode(currency) is false, throw a RangeError exception. - else if (!is_well_formed_currency_code(currency.as_string().utf8_string_view())) { + else if (!is_well_formed_currency_code(currency.as_string().utf8_string())) { return vm.throw_completion(ErrorType::OptionIsNotValidValue, currency, "currency"sv); } @@ -413,7 +413,7 @@ ThrowCompletionOr set_number_format_unit_options(VM& vm, NumberFormat& int } // 10. Else, // a. If IsWellFormedUnitIdentifier(unit) is false, throw a RangeError exception. - else if (!is_well_formed_unit_identifier(unit.as_string().utf8_string_view())) { + else if (!is_well_formed_unit_identifier(unit.as_string().utf8_string())) { return vm.throw_completion(ErrorType::OptionIsNotValidValue, unit, "unit"sv); } @@ -426,10 +426,10 @@ ThrowCompletionOr set_number_format_unit_options(VM& vm, NumberFormat& int intl_object.set_currency(MUST(currency.as_string().utf8_string().to_uppercase())); // c. Set intlObj.[[CurrencyDisplay]] to currencyDisplay. - intl_object.set_currency_display(currency_display.as_string().utf8_string_view()); + intl_object.set_currency_display(currency_display.as_string().utf8_string()); // d. Set intlObj.[[CurrencySign]] to currencySign. - intl_object.set_currency_sign(currency_sign.as_string().utf8_string_view()); + intl_object.set_currency_sign(currency_sign.as_string().utf8_string()); } // 13. If style is "unit", then @@ -438,7 +438,7 @@ ThrowCompletionOr set_number_format_unit_options(VM& vm, NumberFormat& int intl_object.set_unit(unit.as_string().utf8_string()); // b. Set intlObj.[[UnitDisplay]] to unitDisplay. - intl_object.set_unit_display(unit_display.as_string().utf8_string_view()); + intl_object.set_unit_display(unit_display.as_string().utf8_string()); } // 14. Return UNUSED. diff --git a/Libraries/LibJS/Runtime/Intl/PluralRulesConstructor.cpp b/Libraries/LibJS/Runtime/Intl/PluralRulesConstructor.cpp index b21445777e..e9f36caff8 100644 --- a/Libraries/LibJS/Runtime/Intl/PluralRulesConstructor.cpp +++ b/Libraries/LibJS/Runtime/Intl/PluralRulesConstructor.cpp @@ -67,13 +67,13 @@ ThrowCompletionOr> PluralRulesConstructor::construct(FunctionObj auto type = TRY(get_option(vm, *options, vm.names.type, OptionType::String, AK::Array { "cardinal"sv, "ordinal"sv }, "cardinal"sv)); // 8. Set pluralRules.[[Type]] to t. - plural_rules->set_type(type.as_string().utf8_string_view()); + plural_rules->set_type(type.as_string().utf8_string()); // 9. Let notation be ? GetOption(options, "notation", string, « "standard", "scientific", "engineering", "compact" », "standard"). auto notation = TRY(get_option(vm, *options, vm.names.notation, OptionType::String, { "standard"sv, "scientific"sv, "engineering"sv, "compact"sv }, "standard"sv)); // 10. Set pluralRules.[[Notation]] to notation. - plural_rules->set_notation(notation.as_string().utf8_string_view()); + plural_rules->set_notation(notation.as_string().utf8_string()); // 11. Let compactDisplay be ? GetOption(options, "compactDisplay", string, « "short", "long" », "short"). auto compact_display = TRY(get_option(vm, *options, vm.names.compactDisplay, OptionType::String, { "short"sv, "long"sv }, "short"sv)); @@ -81,7 +81,7 @@ ThrowCompletionOr> PluralRulesConstructor::construct(FunctionObj // 12. If notation is "compact", then if (plural_rules->notation() == Unicode::Notation::Compact) { // a. Set pluralRules.[[CompactDisplay]] to compactDisplay. - plural_rules->set_compact_display(compact_display.as_string().utf8_string_view()); + plural_rules->set_compact_display(compact_display.as_string().utf8_string()); } // 13. Perform ? SetNumberFormatDigitOptions(pluralRules, options, 0, 3, notation). diff --git a/Libraries/LibJS/Runtime/Intl/RelativeTimeFormatConstructor.cpp b/Libraries/LibJS/Runtime/Intl/RelativeTimeFormatConstructor.cpp index d101a9859f..724246badc 100644 --- a/Libraries/LibJS/Runtime/Intl/RelativeTimeFormatConstructor.cpp +++ b/Libraries/LibJS/Runtime/Intl/RelativeTimeFormatConstructor.cpp @@ -75,13 +75,13 @@ ThrowCompletionOr> RelativeTimeFormatConstructor::construct(Func auto style = TRY(get_option(vm, *options, vm.names.style, OptionType::String, { "long"sv, "short"sv, "narrow"sv }, "long"sv)); // 11. Set relativeTimeFormat.[[Style]] to style. - relative_time_format->set_style(style.as_string().utf8_string_view()); + relative_time_format->set_style(style.as_string().utf8_string()); // 12. Let numeric be ? GetOption(options, "numeric", STRING, « "always", "auto" », "always"). auto numeric = TRY(get_option(vm, *options, vm.names.numeric, OptionType::String, { "always"sv, "auto"sv }, "always"sv)); // 13. Set relativeTimeFormat.[[Numeric]] to numeric. - relative_time_format->set_numeric(numeric.as_string().utf8_string_view()); + relative_time_format->set_numeric(numeric.as_string().utf8_string()); // 14. Let nfOptions be OrdinaryObjectCreate(null). // 15. Perform ! CreateDataPropertyOrThrow(nfOptions, "numberingSystem", relativeTimeFormat.[[NumberingSystem]]). diff --git a/Libraries/LibJS/Runtime/Intl/SegmenterConstructor.cpp b/Libraries/LibJS/Runtime/Intl/SegmenterConstructor.cpp index 321fc6ae56..288838655c 100644 --- a/Libraries/LibJS/Runtime/Intl/SegmenterConstructor.cpp +++ b/Libraries/LibJS/Runtime/Intl/SegmenterConstructor.cpp @@ -67,7 +67,7 @@ ThrowCompletionOr> SegmenterConstructor::construct(FunctionObjec auto granularity = TRY(get_option(vm, *options, vm.names.granularity, OptionType::String, { "grapheme"sv, "word"sv, "sentence"sv }, "grapheme"sv)); // 9. Set segmenter.[[SegmenterGranularity]] to granularity. - segmenter->set_segmenter_granularity(granularity.as_string().utf8_string_view()); + segmenter->set_segmenter_granularity(granularity.as_string().utf8_string()); auto locale_segmenter = Unicode::Segmenter::create(segmenter->locale(), segmenter->segmenter_granularity()); segmenter->set_segmenter(move(locale_segmenter)); diff --git a/Libraries/LibJS/Runtime/IteratorConstructor.cpp b/Libraries/LibJS/Runtime/IteratorConstructor.cpp index 8964196969..384d73998d 100644 --- a/Libraries/LibJS/Runtime/IteratorConstructor.cpp +++ b/Libraries/LibJS/Runtime/IteratorConstructor.cpp @@ -488,7 +488,7 @@ static ThrowCompletionOr get_zip_mode(VM& vm, Object const& options) // 5. If mode is not one of "shortest", "longest", or "strict", throw a TypeError exception. if (mode.is_string()) { - auto mode_string = mode.as_string().utf8_string_view(); + auto mode_string = mode.as_string().utf16_string_view(); if (mode_string == "shortest"sv) return ZipMode::Shortest; diff --git a/Libraries/LibJS/Runtime/ObjectPrototype.cpp b/Libraries/LibJS/Runtime/ObjectPrototype.cpp index 0ae7f9a905..fadc42890e 100644 --- a/Libraries/LibJS/Runtime/ObjectPrototype.cpp +++ b/Libraries/LibJS/Runtime/ObjectPrototype.cpp @@ -187,12 +187,15 @@ JS_DEFINE_NATIVE_FUNCTION(ObjectPrototype::to_string) // Optimization: Instead of creating another PrimitiveString from builtin_tag, we separate tag and to_string_tag and add an additional branch to step 16. StringView tag; + String custom_tag; // 16. If Type(tag) is not String, set tag to builtinTag. if (!to_string_tag.is_string()) tag = builtin_tag; - else - tag = to_string_tag.as_string().utf8_string_view(); + else { + custom_tag = to_string_tag.as_string().utf8_string(); + tag = custom_tag; + } // 17. Return the string-concatenation of "[object ", tag, and "]". diff --git a/Libraries/LibJS/Runtime/PrimitiveString.cpp b/Libraries/LibJS/Runtime/PrimitiveString.cpp index 2fb3cef1e1..28f5e9d14f 100644 --- a/Libraries/LibJS/Runtime/PrimitiveString.cpp +++ b/Libraries/LibJS/Runtime/PrimitiveString.cpp @@ -9,11 +9,9 @@ #include #include #include -#include #include #include #include -#include #include #include #include @@ -37,32 +35,12 @@ Optional PrimitiveString::short_flat_string_storage_view() const if (m_deferred_kind != DeferredKind::None) return {}; - if (m_utf8_string.has_value() && m_utf8_string->is_short_string()) - return m_utf8_string->bytes_as_string_view(); - if (m_utf16_string.has_value() && m_utf16_string->has_short_ascii_storage()) return m_utf16_string->ascii_view(); return {}; } -static bool utf8_views_form_surrogate_pair_across_boundary(StringView lhs, StringView rhs) -{ - if (lhs.length() < 3 || rhs.length() < 3) - return false; - - // Surrogates encoded as UTF-8 are 3 bytes. - if ((static_cast(lhs[lhs.length() - 3]) & 0xf0) != 0xe0) - return false; - if ((static_cast(rhs[0]) & 0xf0) != 0xe0) - return false; - - auto high_surrogate = *Utf8View(lhs.substring_view(lhs.length() - 3)).begin(); - auto low_surrogate = *Utf8View(rhs).begin(); - return AK::UnicodeUtils::is_utf16_high_surrogate(high_surrogate) - && AK::UnicodeUtils::is_utf16_low_surrogate(low_surrogate); -} - GC::Ptr PrimitiveString::try_create_short_flat_concatenated_string(VM& vm, PrimitiveString const& lhs, PrimitiveString const& rhs) { auto lhs_view = lhs.short_flat_string_storage_view(); @@ -77,9 +55,6 @@ GC::Ptr PrimitiveString::try_create_short_flat_concatenated_str if (byte_count > String::MAX_SHORT_STRING_BYTE_COUNT) return nullptr; - if (utf8_views_form_surrogate_pair_across_boundary(*lhs_view, *rhs_view)) - return nullptr; - AK::Array buffer; lhs_view->bytes().copy_to({ buffer.data(), lhs_view->length() }); rhs_view->bytes().copy_to({ buffer.data() + lhs_view->length(), rhs_view->length() }); @@ -125,29 +100,7 @@ GC::Ref PrimitiveString::create(VM& vm, Utf16FlyString const& s GC::Ref PrimitiveString::create(VM& vm, String const& string) { - if (string.is_empty()) - return vm.empty_string(); - - auto const length_in_code_units = string.length_in_code_units(); - - if (length_in_code_units == 1) { - auto bytes = string.bytes(); - if (auto ch = bytes[0]; is_ascii(ch)) - return vm.single_ascii_character_string(ch); - } - - if (string.length_in_code_units() > MAX_LENGTH_FOR_STRING_CACHE) { - return vm.heap().allocate(string); - } - - auto& string_cache = vm.string_cache(); - if (auto it = string_cache.find(string); it != string_cache.end()) - return *it->value; - - auto new_string = vm.heap().allocate(string); - new_string->m_utf8_string_is_in_cache = true; - string_cache.set(move(string), new_string); - return *new_string; + return create(vm, Utf16String::from_utf8(string.bytes_as_string_view())); } GC::Ref PrimitiveString::create(VM& vm, StringView string) @@ -224,18 +177,11 @@ PrimitiveString::PrimitiveString(Utf16String string) { } -PrimitiveString::PrimitiveString(String string) - : m_utf8_string(move(string)) -{ -} - PrimitiveString::~PrimitiveString() = default; size_t PrimitiveString::external_memory_size() const { size_t size = 0; - if (m_utf8_string.has_value()) - size += string_external_memory_size(*m_utf8_string); if (m_utf16_string.has_value()) size = saturating_add_external_memory_size(size, utf16_string_external_memory_size(*m_utf16_string)); return size; @@ -249,11 +195,6 @@ void PrimitiveString::finalize() if (string.length_in_code_units() <= MAX_LENGTH_FOR_STRING_CACHE) vm().utf16_string_cache().remove(string); } - if (m_utf8_string_is_in_cache) { - auto const& string = *m_utf8_string; - if (string.length_in_code_units() <= MAX_LENGTH_FOR_STRING_CACHE) - vm().string_cache().remove(string); - } } bool PrimitiveString::is_empty() const @@ -267,44 +208,19 @@ bool PrimitiveString::is_empty() const if (has_utf16_string()) return m_utf16_string->is_empty(); - if (has_utf8_string()) - return m_utf8_string->is_empty(); VERIFY_NOT_REACHED(); } String PrimitiveString::utf8_string() const { - resolve_if_needed(EncodingPreference::UTF8); - - if (!has_utf8_string()) { - VERIFY(has_utf16_string()); - m_utf8_string = m_utf16_string->to_utf8(); - } - - return *m_utf8_string; -} - -StringView PrimitiveString::utf8_string_view() const -{ - if (!has_utf8_string()) { - if (has_utf16_string() && m_utf16_string->has_ascii_storage()) - return m_utf16_string->ascii_view(); - - (void)utf8_string(); - } - - return m_utf8_string->bytes_as_string_view(); + return utf16_string_view().to_utf8_but_should_be_ported_to_utf16(); } Utf16String PrimitiveString::utf16_string() const { - resolve_if_needed(EncodingPreference::UTF16); - - if (!has_utf16_string()) { - VERIFY(has_utf8_string()); - m_utf16_string = Utf16String::from_utf8(*m_utf8_string); - } + resolve_if_needed(); + VERIFY(has_utf16_string()); return *m_utf16_string; } @@ -333,8 +249,6 @@ bool PrimitiveString::operator==(PrimitiveString const& other) const return true; if (length_in_utf16_code_units() != other.length_in_utf16_code_units()) return false; - if (m_utf8_string.has_value() && other.m_utf8_string.has_value()) - return m_utf8_string->bytes_as_string_view() == other.m_utf8_string->bytes_as_string_view(); if (m_utf16_string.has_value() && other.m_utf16_string.has_value()) return *m_utf16_string == *other.m_utf16_string; return utf16_string_view() == other.utf16_string_view(); @@ -362,29 +276,28 @@ ThrowCompletionOr> PrimitiveString::get(VM& vm, PropertyKey cons return create(vm, *this, index.as_index(), 1); } -void PrimitiveString::resolve_if_needed(EncodingPreference preference) const +void PrimitiveString::resolve_if_needed() const { switch (m_deferred_kind) { case DeferredKind::None: return; case DeferredKind::Rope: - static_cast(*this).resolve(preference); + static_cast(*this).resolve(); return; case DeferredKind::Substring: - static_cast(*this).resolve(preference); + static_cast(*this).resolve(); return; } VERIFY_NOT_REACHED(); } -void RopeString::resolve(EncodingPreference preference) const +void RopeString::resolve() const { // This vector will hold all the pieces of the rope that need to be assembled // into the resolved string. Vector pieces; - size_t approximate_length = 0; size_t length_in_utf16_code_units = 0; // NOTE: We traverse the rope tree without using recursion, since we'd run out of @@ -401,91 +314,16 @@ void RopeString::resolve(EncodingPreference preference) const continue; } - if (current->has_utf8_string()) - approximate_length += current->utf8_string_view().length(); - if (preference == EncodingPreference::UTF16) - length_in_utf16_code_units += current->length_in_utf16_code_units(); + length_in_utf16_code_units += current->length_in_utf16_code_units(); pieces.append(current); } - if (preference == EncodingPreference::UTF16) { - // The caller wants a UTF-16 string, so we can simply concatenate all the pieces - // into a UTF-16 code unit buffer and create a Utf16String from it. - Utf16StringBuilder builder(length_in_utf16_code_units); - - for (auto const* current : pieces) - builder.append(current->utf16_string_view()); - - m_utf16_string = builder.to_string(); - m_deferred_kind = DeferredKind::None; - m_lhs = nullptr; - m_rhs = nullptr; - return; - } - - // Now that we have all the pieces, we can concatenate them using a StringBuilder. - StringBuilder builder(approximate_length); - - // We keep track of the previous piece in order to handle surrogate pairs spread across two pieces. - PrimitiveString const* previous = nullptr; + Utf16StringBuilder builder(length_in_utf16_code_units); for (auto const* current : pieces) { - if (!previous) { - // This is the very first piece, just append it and continue. - builder.append(current->utf8_string()); - previous = current; - continue; - } - - // Get the UTF-8 representations for both strings. - auto current_string_as_utf8 = current->utf8_string_view(); - auto previous_string_as_utf8 = previous->utf8_string_view(); - - // NOTE: Now we need to look at the end of the previous string and the start - // of the current string, to see if they should be combined into a surrogate. - - // Surrogates encoded as UTF-8 are 3 bytes. - if ((previous_string_as_utf8.length() < 3) || (current_string_as_utf8.length() < 3)) { - builder.append(current_string_as_utf8); - previous = current; - continue; - } - - // Might the previous string end with a UTF-8 encoded surrogate? - if ((static_cast(previous_string_as_utf8[previous_string_as_utf8.length() - 3]) & 0xf0) != 0xe0) { - // If not, just append the current string and continue. - builder.append(current_string_as_utf8); - previous = current; - continue; - } - - // Might the current string begin with a UTF-8 encoded surrogate? - if ((static_cast(current_string_as_utf8[0]) & 0xf0) != 0xe0) { - // If not, just append the current string and continue. - builder.append(current_string_as_utf8); - previous = current; - continue; - } - - auto high_surrogate = *Utf8View(previous_string_as_utf8.substring_view(previous_string_as_utf8.length() - 3)).begin(); - auto low_surrogate = *Utf8View(current_string_as_utf8).begin(); - - if (!AK::UnicodeUtils::is_utf16_high_surrogate(high_surrogate) || !AK::UnicodeUtils::is_utf16_low_surrogate(low_surrogate)) { - builder.append(current_string_as_utf8); - previous = current; - continue; - } - - // Remove 3 bytes from the builder and replace them with the UTF-8 encoded code point. - builder.trim(3); - builder.append_code_point(AK::UnicodeUtils::decode_utf16_surrogate_pair(high_surrogate, low_surrogate)); - - // Append the remaining part of the current string. - builder.append(current_string_as_utf8.substring_view(3)); - previous = current; + builder.append(current->utf16_string_view()); } - // NOTE: We've already produced valid UTF-8 above, so there's no need for additional validation. - m_utf8_string = builder.to_string_without_validation(); + m_utf16_string = builder.to_string(); m_deferred_kind = DeferredKind::None; m_lhs = nullptr; m_rhs = nullptr; @@ -507,17 +345,11 @@ void RopeString::visit_edges(Cell::Visitor& visitor) visitor.visit(m_rhs); } -void Substring::resolve(EncodingPreference preference) const +void Substring::resolve() const { auto source_view = m_source_string->utf16_string_view().substring_view(m_code_unit_offset, m_code_unit_length); - if (preference == EncodingPreference::UTF16) { - m_utf16_string = Utf16String::from_utf16(source_view); - } else { - auto substring = Utf16String::from_utf16(source_view); - m_utf8_string = substring.to_utf8(); - } - + m_utf16_string = Utf16String::from_utf16(source_view); m_deferred_kind = DeferredKind::None; m_source_string = nullptr; } diff --git a/Libraries/LibJS/Runtime/PrimitiveString.h b/Libraries/LibJS/Runtime/PrimitiveString.h index a9fd6b217f..c04b94b123 100644 --- a/Libraries/LibJS/Runtime/PrimitiveString.h +++ b/Libraries/LibJS/Runtime/PrimitiveString.h @@ -48,8 +48,6 @@ public: bool is_empty() const; [[nodiscard]] String utf8_string() const; - [[nodiscard]] StringView utf8_string_view() const; - bool has_utf8_string() const { return m_utf8_string.has_value(); } [[nodiscard]] Utf16String utf16_string() const; [[nodiscard]] Utf16View utf16_string_view() const; @@ -75,17 +73,10 @@ protected: mutable DeferredKind m_deferred_kind { DeferredKind::None }; - mutable Optional m_utf8_string; mutable Optional m_utf16_string; - bool m_utf8_string_is_in_cache { false }; bool m_utf16_string_is_in_cache { false }; - enum class EncodingPreference { - UTF8, - UTF16, - }; - private: friend class RopeString; friend class Substring; @@ -94,9 +85,8 @@ private: virtual size_t external_memory_size() const override; explicit PrimitiveString(Utf16String); - explicit PrimitiveString(String); - void resolve_if_needed(EncodingPreference) const; + void resolve_if_needed() const; Optional short_flat_string_storage_view() const; static GC::Ptr try_create_short_flat_concatenated_string(VM&, PrimitiveString const& lhs, PrimitiveString const& rhs); }; @@ -115,7 +105,7 @@ private: virtual void visit_edges(Visitor&) override; - void resolve(EncodingPreference) const; + void resolve() const; mutable GC::Ptr m_lhs; mutable GC::Ptr m_rhs; @@ -135,7 +125,7 @@ private: virtual void visit_edges(Visitor&) override; - void resolve(EncodingPreference) const; + void resolve() const; mutable GC::Ptr m_source_string; size_t m_code_unit_offset { 0 }; diff --git a/Libraries/LibJS/Runtime/Temporal/AbstractOperations.cpp b/Libraries/LibJS/Runtime/Temporal/AbstractOperations.cpp index 51ee087f90..e3712ac9d4 100644 --- a/Libraries/LibJS/Runtime/Temporal/AbstractOperations.cpp +++ b/Libraries/LibJS/Runtime/Temporal/AbstractOperations.cpp @@ -102,7 +102,7 @@ ThrowCompletionOr get_temporal_disambiguation_option(VM& vm, Obj { // 1. Let stringValue be ? GetOption(options, "disambiguation", STRING, « "compatible", "earlier", "later", "reject" », "compatible"). auto string_value = TRY(get_option(vm, options, vm.names.disambiguation, OptionType::String, { "compatible"sv, "earlier"sv, "later"sv, "reject"sv }, "compatible"sv)); - auto string_view = string_value.as_string().utf8_string_view(); + auto string_view = string_value.as_string().utf8_string(); // 2. If stringValue is "compatible", return COMPATIBLE. if (string_view == "compatible"sv) @@ -166,7 +166,7 @@ ThrowCompletionOr get_temporal_offset_option(VM& vm, Object const& // 5. Let stringValue be ? GetOption(options, "offset", STRING, « "prefer", "use", "ignore", "reject" », stringFallback). auto string_value = TRY(get_option(vm, options, vm.names.offset, OptionType::String, { "prefer"sv, "use"sv, "ignore"sv, "reject"sv }, string_fallback)); - auto string_view = string_value.as_string().utf8_string_view(); + auto string_view = string_value.as_string().utf8_string(); // 6. If stringValue is "prefer", return PREFER. if (string_view == "prefer"sv) @@ -189,7 +189,7 @@ ThrowCompletionOr get_temporal_show_calendar_name_option(VM& vm, O { // 1. Let stringValue be ? GetOption(options, "calendarName", STRING, « "auto", "always", "never", "critical" », "auto"). auto string_value = TRY(get_option(vm, options, vm.names.calendarName, OptionType::String, { "auto"sv, "always"sv, "never"sv, "critical"sv }, "auto"sv)); - auto string_view = string_value.as_string().utf8_string_view(); + auto string_view = string_value.as_string().utf8_string(); // 2. If stringValue is "always", return ALWAYS. if (string_view == "always"sv) @@ -212,7 +212,7 @@ ThrowCompletionOr get_temporal_show_time_zone_name_option(VM& { // 1. Let stringValue be ? GetOption(options, "timeZoneName", STRING, « "auto", "never", "critical" », "auto"). auto string_value = TRY(get_option(vm, options, vm.names.timeZoneName, OptionType::String, { "auto"sv, "never"sv, "critical"sv }, "auto"sv)); - auto string_view = string_value.as_string().utf8_string_view(); + auto string_view = string_value.as_string().utf8_string(); // 2. If stringValue is "never", return NEVER. if (string_view == "never"sv) @@ -231,7 +231,7 @@ ThrowCompletionOr get_temporal_show_offset_option(VM& vm, Object con { // 1. Let stringValue be ? GetOption(options, "offset", STRING, « "auto", "never" », "auto"). auto string_value = TRY(get_option(vm, options, vm.names.offset, OptionType::String, { "auto"sv, "never"sv }, "auto"sv)); - auto string_view = string_value.as_string().utf8_string_view(); + auto string_view = string_value.as_string().utf8_string(); // 2. If stringValue is "never", return never. if (string_view == "never"sv) @@ -246,7 +246,7 @@ ThrowCompletionOr get_direction_option(VM& vm, Object const& options) { // 1. Let stringValue be ? GetOption(options, "direction", STRING, « "next", "previous" », REQUIRED). auto string_value = TRY(get_option(vm, options, vm.names.direction, OptionType::String, { "next"sv, "previous"sv }, Required {})); - auto string_view = string_value.as_string().utf8_string_view(); + auto string_view = string_value.as_string().utf8_string(); // 2. If stringValue is "next", return NEXT. if (string_view == "next"sv) @@ -415,7 +415,7 @@ ThrowCompletionOr get_temporal_unit_valued_option(VM& vm, Object cons if (value.is_undefined()) return UnitValue { Unset {} }; - auto value_string = value.as_string().utf8_string_view(); + auto value_string = value.as_string().utf8_string(); // 8. If value is "auto", return AUTO. if (value_string == "auto"sv) @@ -544,7 +544,7 @@ ThrowCompletionOr get_temporal_relative_to_option(VM& vm, Object con return vm.throw_completion(ErrorType::NotAString, vm.names.relativeTo); // b. Let result be ? ParseISODateTime(value, « TemporalDateTimeString[+Zoned], TemporalDateTimeString[~Zoned] »). - auto result = TRY(parse_iso_date_time(vm, value.as_string().utf8_string_view(), { { Production::TemporalZonedDateTimeString, Production::TemporalDateTimeString } })); + auto result = TRY(parse_iso_date_time(vm, value.as_string().utf8_string(), { { Production::TemporalZonedDateTimeString, Production::TemporalDateTimeString } })); // c. Let offsetString be result.[[TimeZone]].[[OffsetString]]. offset_string = move(result.time_zone.offset_string); @@ -1620,7 +1620,7 @@ ThrowCompletionOr to_offset_string(VM& vm, Value argument) return vm.throw_completion(ErrorType::TemporalInvalidTimeZoneString, offset); // 3. Perform ? ParseDateTimeUTCOffset(offset). - TRY(parse_date_time_utc_offset(vm, offset.as_string().utf8_string_view())); + TRY(parse_date_time_utc_offset(vm, offset.as_string().utf8_string())); // 4. Return offset. return offset.as_string().utf8_string(); diff --git a/Libraries/LibJS/Runtime/Temporal/Calendar.cpp b/Libraries/LibJS/Runtime/Temporal/Calendar.cpp index 5c89a6657e..d0d7e00cd3 100644 --- a/Libraries/LibJS/Runtime/Temporal/Calendar.cpp +++ b/Libraries/LibJS/Runtime/Temporal/Calendar.cpp @@ -318,7 +318,7 @@ ThrowCompletionOr parse_month_code(VM& vm, Value argument) if (!month_code.is_string()) return vm.throw_completion(ErrorType::NotAString, month_code); - return parse_month_code(vm, month_code.as_string().utf8_string_view()); + return parse_month_code(vm, month_code.as_string().utf8_string()); } // 12.2.1 ParseMonthCode ( argument ), https://tc39.es/proposal-temporal/#sec-temporal-parsemonthcode diff --git a/Libraries/LibJS/Runtime/Temporal/Duration.cpp b/Libraries/LibJS/Runtime/Temporal/Duration.cpp index fcbee978af..922c4f9df3 100644 --- a/Libraries/LibJS/Runtime/Temporal/Duration.cpp +++ b/Libraries/LibJS/Runtime/Temporal/Duration.cpp @@ -361,7 +361,7 @@ ThrowCompletionOr> to_temporal_duration(VM& vm, Value item) return vm.throw_completion(ErrorType::NotAString, item); // b. Return ? ParseTemporalDurationString(item). - return TRY(parse_temporal_duration_string(vm, item.as_string().utf8_string_view())); + return TRY(parse_temporal_duration_string(vm, item.as_string().utf8_string())); } // 3. Let result be a new Partial Duration Record with each field set to 0. diff --git a/Libraries/LibJS/Runtime/Temporal/Instant.cpp b/Libraries/LibJS/Runtime/Temporal/Instant.cpp index 730828334f..ad753e667a 100644 --- a/Libraries/LibJS/Runtime/Temporal/Instant.cpp +++ b/Libraries/LibJS/Runtime/Temporal/Instant.cpp @@ -111,7 +111,7 @@ ThrowCompletionOr> to_temporal_instant(VM& vm, Value item) return vm.throw_completion(ErrorType::TemporalInvalidInstantString, item); // 3. Let parsed be ? ParseISODateTime(item, « TemporalInstantString »). - auto parsed = TRY(parse_iso_date_time(vm, item.as_string().utf8_string_view(), { { Production::TemporalInstantString } })); + auto parsed = TRY(parse_iso_date_time(vm, item.as_string().utf8_string(), { { Production::TemporalInstantString } })); // 4. Assert: Either parsed.[[TimeZone]].[[OffsetString]] is not empty or parsed.[[TimeZone]].[[Z]] is true, but not both. auto const& offset_string = parsed.time_zone.offset_string; diff --git a/Libraries/LibJS/Runtime/Temporal/PlainDate.cpp b/Libraries/LibJS/Runtime/Temporal/PlainDate.cpp index 497b87fc06..d9546b80e2 100644 --- a/Libraries/LibJS/Runtime/Temporal/PlainDate.cpp +++ b/Libraries/LibJS/Runtime/Temporal/PlainDate.cpp @@ -135,7 +135,7 @@ ThrowCompletionOr> to_temporal_date(VM& vm, Value item, Value return vm.throw_completion(ErrorType::TemporalInvalidPlainDate); // 4. Let result be ? ParseISODateTime(item, « TemporalDateTimeString[~Zoned] »). - auto result = TRY(parse_iso_date_time(vm, item.as_string().utf8_string_view(), { { Production::TemporalDateTimeString } })); + auto result = TRY(parse_iso_date_time(vm, item.as_string().utf8_string(), { { Production::TemporalDateTimeString } })); // 5. Let calendar be result.[[Calendar]]. // 6. If calendar is empty, set calendar to "iso8601". diff --git a/Libraries/LibJS/Runtime/Temporal/PlainDateConstructor.cpp b/Libraries/LibJS/Runtime/Temporal/PlainDateConstructor.cpp index 8a2791b79a..5be5d6cabf 100644 --- a/Libraries/LibJS/Runtime/Temporal/PlainDateConstructor.cpp +++ b/Libraries/LibJS/Runtime/Temporal/PlainDateConstructor.cpp @@ -72,7 +72,7 @@ ThrowCompletionOr> PlainDateConstructor::construct(FunctionObjec return vm.throw_completion(ErrorType::NotAString, "calendar"sv); // 7. Set calendar to ? CanonicalizeCalendar(calendar). - auto calendar = TRY(canonicalize_calendar(vm, calendar_value.as_string().utf8_string_view())); + auto calendar = TRY(canonicalize_calendar(vm, calendar_value.as_string().utf8_string())); // 8. If IsValidISODate(y, m, d) is false, throw a RangeError exception. if (!is_valid_iso_date(year, month, day)) diff --git a/Libraries/LibJS/Runtime/Temporal/PlainDateTime.cpp b/Libraries/LibJS/Runtime/Temporal/PlainDateTime.cpp index b692ed304f..5ac15f48a6 100644 --- a/Libraries/LibJS/Runtime/Temporal/PlainDateTime.cpp +++ b/Libraries/LibJS/Runtime/Temporal/PlainDateTime.cpp @@ -175,7 +175,7 @@ ThrowCompletionOr> to_temporal_date_time(VM& vm, Value it return vm.throw_completion(ErrorType::TemporalInvalidPlainDateTime); // 4. Let result be ? ParseISODateTime(item, « TemporalDateTimeString[~Zoned] »). - auto result = TRY(parse_iso_date_time(vm, item.as_string().utf8_string_view(), { { Production::TemporalDateTimeString } })); + auto result = TRY(parse_iso_date_time(vm, item.as_string().utf8_string(), { { Production::TemporalDateTimeString } })); // 5. If result.[[Time]] is START-OF-DAY, let time be MidnightTimeRecord(); else let time be result.[[Time]]. auto time = result.time.has() ? midnight_time_record() : result.time.get