@@ -333,22 +333,33 @@ JS_DEFINE_NATIVE_FUNCTION(Uint8ArrayPrototypeHelpers::to_base64)
333333 }
334334
335335 // 8. Let toEncode be ? GetUint8ArrayBytes(O).
336- auto to_encode = TRY (get_uint8_array_bytes (vm, typed_array));
337-
338336 String out_ascii;
339337
340- // 9. If alphabet is "base64", then
341- if (alphabet == Alphabet::Base64) {
342- // a. Let outAscii be the sequence of code points which results from encoding toEncode according to the base64
343- // encoding specified in section 4 of RFC 4648. Padding is included if and only if omitPadding is false.
344- out_ascii = MUST (encode_base64 (to_encode, omit_padding));
345- }
346- // 10. Else,
347- else {
348- // a. Assert: alphabet is "base64url".
349- // b. Let outAscii be the sequence of code points which results from encoding toEncode according to the base64url
350- // encoding specified in section 5 of RFC 4648. Padding is included if and only if omitPadding is false.
351- out_ascii = MUST (encode_base64url (to_encode, omit_padding));
338+ // OPTIMIZATION: If the ArrayBuffer is not shared, we can avoid copying the bytes.
339+ if (!typed_array->viewed_array_buffer ()->is_shared_array_buffer ()
340+ && !typed_array->viewed_array_buffer ()->is_detached ()) {
341+ auto to_encode = TRY (get_uint8_array_bytes_view (vm, typed_array));
342+ if (alphabet == Alphabet::Base64) {
343+ out_ascii = MUST (encode_base64 (to_encode, omit_padding));
344+ } else {
345+ out_ascii = MUST (encode_base64url (to_encode, omit_padding));
346+ }
347+ } else {
348+ auto to_encode = TRY (get_uint8_array_bytes (vm, typed_array));
349+
350+ // 9. If alphabet is "base64", then
351+ if (alphabet == Alphabet::Base64) {
352+ // a. Let outAscii be the sequence of code points which results from encoding toEncode according to the base64
353+ // encoding specified in section 4 of RFC 4648. Padding is included if and only if omitPadding is false.
354+ out_ascii = MUST (encode_base64 (to_encode, omit_padding));
355+ }
356+ // 10. Else,
357+ else {
358+ // a. Assert: alphabet is "base64url".
359+ // b. Let outAscii be the sequence of code points which results from encoding toEncode according to the base64url
360+ // encoding specified in section 5 of RFC 4648. Padding is included if and only if omitPadding is false.
361+ out_ascii = MUST (encode_base64url (to_encode, omit_padding));
362+ }
352363 }
353364
354365 // 11. Return CodePointsToString(outAscii).
@@ -438,6 +449,26 @@ ThrowCompletionOr<ByteBuffer> get_uint8_array_bytes(VM& vm, TypedArrayBase const
438449 return bytes;
439450}
440451
452+ // 23.3.3.2 GetUint8ArrayBytes ( ta ), https://tc39.es/ecma262/#sec-getuint8arraybytes
453+ // NOTE: This is an optimized version that returns a view into the underlying buffer when possible.
454+ // It's only safe to use when the ArrayBuffer is known to not be shared or detached.
455+ ThrowCompletionOr<ReadonlyBytes> get_uint8_array_bytes_view (VM& vm, TypedArrayBase const & typed_array)
456+ {
457+ VERIFY (typed_array.kind () == TypedArrayBase::Kind::Uint8Array);
458+ VERIFY (!typed_array.viewed_array_buffer ()->is_shared_array_buffer ());
459+ VERIFY (!typed_array.viewed_array_buffer ()->is_detached ());
460+ auto typed_array_record = make_typed_array_with_buffer_witness_record (typed_array, ArrayBuffer::Order::SeqCst);
461+ if (is_typed_array_out_of_bounds (typed_array_record))
462+ return vm.throw_completion <TypeError>(ErrorType::BufferOutOfBounds, " TypedArray" sv);
463+ auto length = typed_array_length (typed_array_record);
464+ auto byte_offset = typed_array.byte_offset ();
465+
466+ return ReadonlyBytes {
467+ typed_array.viewed_array_buffer ()->buffer ().data () + byte_offset,
468+ length
469+ };
470+ }
471+
441472// 23.3.3.3 SetUint8ArrayBytes ( into, bytes ), https://tc39.es/ecma262/#sec-setuint8arraybytes
442473void set_uint8_array_bytes (TypedArrayBase& into, ReadonlyBytes bytes)
443474{
0 commit comments