15#include "third_party/simdutf/simdutf.h"
27 "get %TypedArray%.prototype.buffer");
28 return *typed_array->GetBuffer();
33int64_t CapRelativeIndex(
double relative, int64_t minimum, int64_t maximum) {
34 DCHECK(!std::isnan(relative));
35 return static_cast<int64_t
>(
36 relative < 0 ? std::max<double>(relative + maximum, minimum)
37 :
std::min<double>(relative, maximum));
46 const char* method_name =
"%TypedArray%.prototype.copyWithin";
51 int64_t len = array->GetLength();
60 to = CapRelativeIndex(num, 0, len);
62 if (
args.length() > 2) {
65 from = CapRelativeIndex(num, 0, len);
68 if (!IsUndefined(*
end, isolate)) {
71 final = CapRelativeIndex(num, 0, len);
76 int64_t
count = std::min<int64_t>(
final - from, len - to);
77 if (
count <= 0)
return *array;
83 isolate, NewTypeError(MessageTemplate::kDetachedOperation,
84 isolate->factory()->NewStringFromAsciiChecked(
89 bool out_of_bounds =
false;
90 int64_t new_len = array->GetLengthOrOutOfBounds(out_of_bounds);
94 isolate->factory()->NewStringFromAsciiChecked(method_name);
102 if (
final > new_len) {
105 count = std::min<int64_t>(
final - from, new_len - to);
119 size_t element_size = array->element_size();
120 to = to * element_size;
121 from = from * element_size;
124 uint8_t* data =
static_cast<uint8_t*
>(array->DataPtr());
125 if (array->buffer()->is_shared()) {
129 std::memmove(data + to, data + from,
count);
142 const char* method_name =
"%TypedArray%.prototype.fill";
149 int64_t len = array->GetLength();
155 BigInt::FromObject(isolate, obj_value));
165 if (
args.length() > 2) {
176 start = CapRelativeIndex(double_num, 0, len);
180 num =
args.atOrUndefined(isolate, 3);
181 if (!IsUndefined(*num, isolate)) {
187 end = CapRelativeIndex(double_num, 0, len);
196 isolate, NewTypeError(MessageTemplate::kDetachedOperation,
197 isolate->factory()->NewStringFromAsciiChecked(
202 if (array->IsOutOfBounds()) {
205 isolate->factory()->NewStringFromAsciiChecked(method_name);
210 end = std::min(
end,
static_cast<int64_t
>(array->GetLength()));
214 if (
count <= 0)
return *array;
236 const char* method_name =
"%TypedArray%.prototype.includes";
243 int64_t len = array->GetLength();
247 if (
args.length() > 2) {
251 index = CapRelativeIndex(num, 0, len);
257 elements->
IncludesValue(isolate, array, search_element, index, len);
259 return *isolate->factory()->ToBoolean(
result.FromJust());
266 const char* method_name =
"%TypedArray%.prototype.indexOf";
271 int64_t len = array->GetLength();
275 if (
args.length() > 2) {
279 index = CapRelativeIndex(num, 0, len);
284 if (
V8_UNLIKELY(array->IsVariableLength() && array->IsOutOfBounds())) {
291 elements->
IndexOfValue(isolate, array, search_element, index, len);
293 return *isolate->factory()->NewNumberFromInt64(
result.FromJust());
300 const char* method_name =
"%TypedArray%.prototype.lastIndexOf";
305 int64_t len = array->GetLength();
308 int64_t index = len - 1;
309 if (
args.length() > 2) {
315 index = std::min<int64_t>(CapRelativeIndex(num, -1, len), len - 1);
321 if (
V8_UNLIKELY(array->IsVariableLength() && array->IsOutOfBounds())) {
330 return *isolate->factory()->NewNumberFromInt64(
result.FromJust());
337 const char* method_name =
"%TypedArray%.prototype.reverse";
349std::vector<std::tuple<const char*, size_t, simdutf::base64_options>>
350SimdutfBase64OptionsVector() {
351 return {{
"base64", 6, simdutf::base64_options::base64_default},
352 {
"base64url", 9, simdutf::base64_options::base64_url}};
356Maybe<T> MapOptionToEnum(
357 Isolate* isolate, DirectHandle<String> option_string,
358 const std::vector<std::tuple<const char*, size_t, T>>& allowed_options) {
363 String::FlatContent option_content = option_string->GetFlatContent(no_gc);
365 if (option_content.IsOneByte()) {
366 const unsigned char* option_string_to_compare =
367 option_content.ToOneByteVector().data();
368 size_t length = option_content.ToOneByteVector().size();
370 for (
auto& [str_val, str_size, enum_val] : allowed_options) {
371 if (str_size == length &&
378 option_content.ToUC16Vector().data();
379 size_t length = option_content.ToUC16Vector().size();
381 for (
auto& [str_val, str_size, enum_val] : allowed_options) {
382 if (str_size == length &&
390 isolate->Throw(*isolate->factory()->NewTypeError(
391 MessageTemplate::kInvalidOption, option_string));
397 case simdutf::error_code::INVALID_BASE64_CHARACTER:
398 return MessageTemplate::kInvalidBase64Character;
399 case simdutf::error_code::BASE64_INPUT_REMAINDER:
400 return MessageTemplate::kBase64InputRemainder;
401 case simdutf::error_code::BASE64_EXTRA_BITS:
402 return MessageTemplate::kBase64ExtraBits;
409Maybe<simdutf::result> ArrayBufferFromBase64(
410 Isolate* isolate, T input_vector,
size_t input_length,
411 size_t& output_length, simdutf::base64_options alphabet,
412 simdutf::last_chunk_handling_options last_chunk_handling,
413 DirectHandle<JSArrayBuffer>& buffer) {
414 const char method_name[] =
"Uint8Array.fromBase64";
416 output_length = simdutf::maximal_binary_length_from_base64(
417 reinterpret_cast<const T
>(input_vector), input_length);
418 std::unique_ptr<char[]> output = std::make_unique<char[]>(output_length);
419 simdutf::result simd_result = simdutf::base64_to_binary_safe(
420 reinterpret_cast<const T
>(input_vector), input_length, output.get(),
421 output_length, alphabet, last_chunk_handling);
425 MaybeDirectHandle<JSArrayBuffer> result_buffer =
426 isolate->factory()->NewJSArrayBufferAndBackingStore(
428 if (!result_buffer.ToHandle(&buffer)) {
429 isolate->Throw(*isolate->factory()->NewRangeError(
430 MessageTemplate::kOutOfMemory,
431 isolate->factory()->NewStringFromAsciiChecked(method_name)));
435 memcpy(buffer->backing_store(), output.get(), output_length);
448 if (!IsString(*input)) {
450 isolate, NewTypeError(MessageTemplate::kArgumentIsNonString,
451 isolate->factory()->input_string()));
463 isolate, opt_alphabet,
465 options, isolate->factory()->alphabet_string(), isolate));
468 simdutf::base64_options alphabet;
469 if (IsUndefined(*opt_alphabet)) {
470 alphabet = simdutf::base64_default;
471 }
else if (!IsString(*opt_alphabet)) {
473 isolate, NewTypeError(MessageTemplate::kInvalidOption, opt_alphabet));
481 MapOptionToEnum(isolate, alphabet_string,
482 SimdutfBase64OptionsVector()));
488 isolate, opt_last_chunk_handling,
490 options, isolate->factory()->last_chunk_handling_string(), isolate));
493 simdutf::last_chunk_handling_options last_chunk_handling;
494 if (IsUndefined(*opt_last_chunk_handling)) {
495 last_chunk_handling = simdutf::last_chunk_handling_options::loose;
496 }
else if (!IsString(*opt_last_chunk_handling)) {
499 NewTypeError(MessageTemplate::kInvalidOption, opt_last_chunk_handling));
507 std::tuple<const char*, size_t, simdutf::last_chunk_handling_options>>
508 last_chunk_handling_vector = {
509 {
"loose", 5, simdutf::last_chunk_handling_options::loose},
510 {
"strict", 6, simdutf::last_chunk_handling_options::strict},
511 {
"stop-before-partial", 19,
512 simdutf::last_chunk_handling_options::stop_before_partial}};
514 isolate, last_chunk_handling,
515 MapOptionToEnum(isolate, last_chunk_handling_string,
516 last_chunk_handling_vector));
521 size_t output_length;
522 simdutf::result simd_result;
528 const unsigned char* input_vector =
532 isolate, simd_result,
533 ArrayBufferFromBase64(isolate,
534 reinterpret_cast<const char*
>(input_vector),
535 input_length, output_length, alphabet,
536 last_chunk_handling, buffer));
541 isolate, simd_result,
542 ArrayBufferFromBase64(isolate,
543 reinterpret_cast<const char16_t*
>(input_vector),
544 input_length, output_length, alphabet,
545 last_chunk_handling, buffer));
551 if (simd_result.error != simdutf::error_code::SUCCESS) {
553 isolate, NewSyntaxError(ToMessageTemplate(simd_result.error)));
566 return *result_typed_array;
572 const char method_name[] =
"Uint8Array.prototype.toBase64";
577 if (uint8array->GetElementsKind() != ElementsKind::UINT8_ELEMENTS) {
579 isolate, NewTypeError(MessageTemplate::kIncompatibleMethodReceiver,
580 isolate->factory()->NewStringFromAsciiChecked(
590 isolate, opt_alphabet,
592 options, isolate->factory()->alphabet_string(), isolate));
595 simdutf::base64_options alphabet;
596 if (IsUndefined(*opt_alphabet)) {
597 alphabet = simdutf::base64_options::base64_default;
598 }
else if (!IsString(*opt_alphabet)) {
600 isolate, NewTypeError(MessageTemplate::kInvalidOption, opt_alphabet));
608 MapOptionToEnum(isolate, alphabet_string,
609 SimdutfBase64OptionsVector()));
614 bool omit_padding =
false;
616 isolate, omit_padding_object,
618 options, isolate->factory()->NewStringFromAsciiChecked(
"omitPadding"),
625 bool out_of_bounds =
false;
626 size_t length = uint8array->GetLengthOrOutOfBounds(out_of_bounds);
628 if (out_of_bounds || uint8array->WasDetached()) {
630 isolate, NewTypeError(MessageTemplate::kDetachedOperation,
631 isolate->factory()->NewStringFromAsciiChecked(
635 if (alphabet == simdutf::base64_options::base64_default &&
636 omit_padding ==
true) {
637 alphabet = simdutf::base64_options::base64_default_no_padding;
638 }
else if (alphabet == simdutf::base64_options::base64_url &&
639 omit_padding ==
false) {
640 alphabet = simdutf::base64_options::base64_url_with_padding;
643 size_t output_length = simdutf::base64_length_from_binary(length, alphabet);
647 isolate, NewTypeError(MessageTemplate::kInvalidStringLength));
650 if (output_length == 0) {
651 return *isolate->factory()->empty_string();
657 isolate->factory()->NewRawOneByteString(
static_cast<int>(output_length)));
676 size_t simd_result_size = simdutf::binary_to_base64(
677 std::bit_cast<const char*>(uint8array->GetBuffer()->backing_store()),
678 length,
reinterpret_cast<char*
>(output->GetChars(no_gc)), alphabet);
679 DCHECK_EQ(simd_result_size, output_length);
680 USE(simd_result_size);
692 const char method_name[] =
"Uint8Array.fromHex";
696 if (!IsString(*input)) {
698 isolate, NewTypeError(MessageTemplate::kArgumentIsNonString,
699 isolate->factory()->input_string()));
711 size_t input_length = input_string->length();
712 if (input_length % 2 != 0) {
714 isolate, NewSyntaxError(MessageTemplate::kInvalidHexString));
717 size_t output_length = (input_length / 2);
720 isolate->factory()->NewJSArrayBufferAndBackingStore(
723 if (!result_buffer.
ToHandle(&buffer)) {
725 isolate, NewRangeError(MessageTemplate::kOutOfMemory,
726 isolate->factory()->NewStringFromAsciiChecked(
748 isolate, NewSyntaxError(MessageTemplate::kInvalidHexString));
759 return *result_typed_array;
765 const char method_name[] =
"Uint8Array.prototype.toHex";
770 if (uint8array->GetElementsKind() != ElementsKind::UINT8_ELEMENTS) {
772 isolate, NewTypeError(MessageTemplate::kIncompatibleMethodReceiver,
773 isolate->factory()->NewStringFromAsciiChecked(
778 bool out_of_bounds =
false;
779 size_t length = uint8array->GetLengthOrOutOfBounds(out_of_bounds);
781 if (out_of_bounds || uint8array->WasDetached()) {
783 isolate, NewTypeError(MessageTemplate::kDetachedOperation,
784 isolate->factory()->NewStringFromAsciiChecked(
790 isolate, NewTypeError(MessageTemplate::kInvalidStringLength));
794 return *isolate->factory()->empty_string();
798 std::bit_cast<const char*>(uint8array->GetBuffer()->backing_store());
804 isolate->factory()->NewRawOneByteString(
static_cast<int>(length) * 2));
#define CHECK_RECEIVER(Type, name, method)
constexpr size_t size() const
constexpr T * data() const
static ElementsAccessor * ForKind(ElementsKind elements_kind)
virtual Maybe< bool > IncludesValue(Isolate *isolate, DirectHandle< JSObject > receiver, DirectHandle< Object > value, size_t start, size_t length)=0
virtual Maybe< int64_t > LastIndexOfValue(DirectHandle< JSObject > receiver, DirectHandle< Object > value, size_t start)=0
virtual void Reverse(Tagged< JSObject > receiver)=0
virtual Maybe< int64_t > IndexOfValue(Isolate *isolate, DirectHandle< JSObject > receiver, DirectHandle< Object > value, size_t start, size_t length)=0
static MaybeDirectHandle< Object > ReadFromOptionsBag(DirectHandle< Object > options, DirectHandle< String > option_name, Isolate *isolate)
static MaybeDirectHandle< JSTypedArray > Validate(Isolate *isolate, DirectHandle< Object > receiver, const char *method_name)
V8_WARN_UNUSED_RESULT V8_INLINE bool ToHandle(DirectHandle< S > *out) const
static V8_WARN_UNUSED_RESULT HandleType< Number >::MaybeType ToNumber(Isolate *isolate, HandleType< T > input)
static V8_EXPORT_PRIVATE bool BooleanValue(Tagged< Object > obj, IsolateT *isolate)
static V8_WARN_UNUSED_RESULT Maybe< double > IntegerValue(Isolate *isolate, HandleType< T > input)
static constexpr Tagged< Smi > FromInt(int value)
base::Vector< const uint8_t > ToOneByteVector() const
base::Vector< const base::uc16 > ToUC16Vector() const
static const uint32_t kMaxLength
static V8_INLINE HandleType< String > Flatten(Isolate *isolate, HandleType< T > string, AllocationType allocation=AllocationType::kYoung)
#define ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, dst, call)
#define THROW_NEW_ERROR_RETURN_FAILURE(isolate, call)
#define MAYBE_RETURN(call, value)
#define RETURN_RESULT_OR_FAILURE(isolate, call)
#define MAYBE_ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, dst, call)
base::Vector< const DirectHandle< Object > > args
ZoneVector< RpoNumber > & result
void Relaxed_Memmove(volatile Atomic8 *dst, volatile const Atomic8 *src, size_t bytes)
PerThreadAssertScopeDebugOnly< false, SAFEPOINTS_ASSERT, HEAP_ALLOCATION_ASSERT > DisallowGarbageCollection
PerThreadAssertScopeDebugOnly< true, SAFEPOINTS_ASSERT, HEAP_ALLOCATION_ASSERT > AllowGarbageCollection
bool CompareCharsEqual(const lchar *lhs, const rchar *rhs, size_t chars)
bool ArrayBufferFromHex(base::Vector< T > &input_vector, DirectHandle< JSArrayBuffer > buffer, size_t output_length)
bool IsBigIntTypedArrayElementsKind(ElementsKind kind)
Tagged< Object > Uint8ArrayToHex(const char *bytes, size_t length, DirectHandle< SeqOneByteString > string_output)
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
Maybe< T > Just(const T &t)
#define DCHECK_LE(v1, v2)
#define DCHECK_GE(v1, v2)
#define DCHECK(condition)
#define DCHECK_LT(v1, v2)
#define DCHECK_EQ(v1, v2)
#define V8_LIKELY(condition)
#define V8_UNLIKELY(condition)