LibJS: Avoid options object allocation in fromBase64() and toBase64()

When no options (or undefined) are passed into these APIs, the spec has
us synthesize a temporary "options object" to read the options from.

We don't actually need these objects, so let's sidestep the allocation
if we can (and just use the default values in that case).
This commit is contained in:
Andreas Kling 2025-11-29 10:53:18 +01:00 committed by Tim Flynn
parent b2761b5640
commit b6ef80ff36
Notes: github-actions[bot] 2025-11-29 14:41:05 +00:00

View file

@ -89,18 +89,23 @@ JS_DEFINE_NATIVE_FUNCTION(Uint8ArrayConstructorHelpers::from_base64)
if (!string_value.is_string()) if (!string_value.is_string())
return vm.throw_completion<TypeError>(ErrorType::NotAString, string_value); return vm.throw_completion<TypeError>(ErrorType::NotAString, string_value);
// OPTIMIZATION: Avoid allocating an empty options object if none was provided.
Alphabet alphabet = Alphabet::Base64;
AK::LastChunkHandling last_chunk_handling = AK::LastChunkHandling::Loose;
if (!options_value.is_undefined()) {
// 2. Let opts be ? GetOptionsObject(options). // 2. Let opts be ? GetOptionsObject(options).
auto options = TRY(get_options_object(vm, options_value)); auto options = TRY(get_options_object(vm, options_value));
// 3. Let alphabet be ? Get(opts, "alphabet"). // 3. Let alphabet be ? Get(opts, "alphabet").
// 4. If alphabet is undefined, set alphabet to "base64". // 4. If alphabet is undefined, set alphabet to "base64".
// 5. If alphabet is neither "base64" nor "base64url", throw a TypeError exception. // 5. If alphabet is neither "base64" nor "base64url", throw a TypeError exception.
auto alphabet = TRY(parse_alphabet(vm, *options)); alphabet = TRY(parse_alphabet(vm, *options));
// 6. Let lastChunkHandling be ? Get(opts, "lastChunkHandling"). // 6. Let lastChunkHandling be ? Get(opts, "lastChunkHandling").
// 7. If lastChunkHandling is undefined, set lastChunkHandling to "loose". // 7. If lastChunkHandling is undefined, set lastChunkHandling to "loose".
// 8. If lastChunkHandling is not one of "loose", "strict", or "stop-before-partial", throw a TypeError exception. // 8. If lastChunkHandling is not one of "loose", "strict", or "stop-before-partial", throw a TypeError exception.
auto last_chunk_handling = TRY(parse_last_chunk_handling(vm, *options)); last_chunk_handling = TRY(parse_last_chunk_handling(vm, *options));
}
// 9. Let result be FromBase64(string, alphabet, lastChunkHandling). // 9. Let result be FromBase64(string, alphabet, lastChunkHandling).
auto result = JS::from_base64(vm, string_value.as_string().utf8_string_view(), alphabet, last_chunk_handling); auto result = JS::from_base64(vm, string_value.as_string().utf8_string_view(), alphabet, last_chunk_handling);
@ -310,17 +315,22 @@ JS_DEFINE_NATIVE_FUNCTION(Uint8ArrayPrototypeHelpers::to_base64)
// 2. Perform ? ValidateUint8Array(O). // 2. Perform ? ValidateUint8Array(O).
auto typed_array = TRY(validate_uint8_array(vm)); auto typed_array = TRY(validate_uint8_array(vm));
// OPTIMIZATION: Avoid allocating an empty options object if none was provided.
Alphabet alphabet = Alphabet::Base64;
AK::OmitPadding omit_padding = AK::OmitPadding::No;
if (!options_value.is_undefined()) {
// 3. Let opts be ? GetOptionsObject(options). // 3. Let opts be ? GetOptionsObject(options).
auto options = TRY(get_options_object(vm, options_value)); auto options = TRY(get_options_object(vm, options_value));
// 4. Let alphabet be ? Get(opts, "alphabet"). // 4. Let alphabet be ? Get(opts, "alphabet").
// 5. If alphabet is undefined, set alphabet to "base64". // 5. If alphabet is undefined, set alphabet to "base64".
// 6. If alphabet is neither "base64" nor "base64url", throw a TypeError exception. // 6. If alphabet is neither "base64" nor "base64url", throw a TypeError exception.
auto alphabet = TRY(parse_alphabet(vm, *options)); alphabet = TRY(parse_alphabet(vm, *options));
// 7. Let omitPadding be ToBoolean(? Get(opts, "omitPadding")). // 7. Let omitPadding be ToBoolean(? Get(opts, "omitPadding")).
auto omit_padding_value = TRY(options->get(vm.names.omitPadding)).to_boolean(); auto omit_padding_value = TRY(options->get(vm.names.omitPadding)).to_boolean();
auto omit_padding = omit_padding_value ? AK::OmitPadding::Yes : AK::OmitPadding::No; omit_padding = omit_padding_value ? AK::OmitPadding::Yes : AK::OmitPadding::No;
}
// 8. Let toEncode be ? GetUint8ArrayBytes(O). // 8. Let toEncode be ? GetUint8ArrayBytes(O).
auto to_encode = TRY(get_uint8_array_bytes(vm, typed_array)); auto to_encode = TRY(get_uint8_array_bytes(vm, typed_array));