LCOV - code coverage report
Current view: top level - src/builtins - builtins-typed-array-gen.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 768 782 98.2 %
Date: 2019-01-20 Functions: 77 78 98.7 %

          Line data    Source code
       1             : // Copyright 2017 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #include "src/builtins/builtins-typed-array-gen.h"
       6             : 
       7             : #include "src/builtins/builtins-constructor-gen.h"
       8             : #include "src/builtins/builtins-utils-gen.h"
       9             : #include "src/builtins/builtins.h"
      10             : #include "src/builtins/growable-fixed-array-gen.h"
      11             : #include "src/handles-inl.h"
      12             : #include "src/heap/factory-inl.h"
      13             : 
      14             : namespace v8 {
      15             : namespace internal {
      16             : 
      17             : using compiler::Node;
      18             : template <class T>
      19             : using TNode = compiler::TNode<T>;
      20             : 
      21             : // This is needed for gc_mole which will compile this file without the full set
      22             : // of GN defined macros.
      23             : #ifndef V8_TYPED_ARRAY_MAX_SIZE_IN_HEAP
      24             : #define V8_TYPED_ARRAY_MAX_SIZE_IN_HEAP 64
      25             : #endif
      26             : 
      27             : // -----------------------------------------------------------------------------
      28             : // ES6 section 22.2 TypedArray Objects
      29             : 
      30         112 : TNode<Map> TypedArrayBuiltinsAssembler::LoadMapForType(
      31             :     TNode<JSTypedArray> array) {
      32         112 :   TVARIABLE(Map, var_typed_map);
      33         112 :   TNode<Map> array_map = LoadMap(array);
      34         112 :   TNode<Int32T> elements_kind = LoadMapElementsKind(array_map);
      35         112 :   ReadOnlyRoots roots(isolate());
      36             : 
      37             :   DispatchTypedArrayByElementsKind(
      38             :       elements_kind,
      39        1232 :       [&](ElementsKind kind, int size, int typed_array_fun_index) {
      40        1232 :         Handle<Map> map(roots.MapForFixedTypedArray(kind), isolate());
      41        2464 :         var_typed_map = HeapConstant(map);
      42        1456 :       });
      43             : 
      44         112 :   return var_typed_map.value();
      45             : }
      46             : 
      47             : // The byte_offset can be higher than Smi range, in which case to perform the
      48             : // pointer arithmetic necessary to calculate external_pointer, converting
      49             : // byte_offset to an intptr is more difficult. The max byte_offset is 8 * MaxSmi
      50             : // on the particular platform. 32 bit platforms are self-limiting, because we
      51             : // can't allocate an array bigger than our 32-bit arithmetic range anyway. 64
      52             : // bit platforms could theoretically have an offset up to 2^35 - 1, so we may
      53             : // need to convert the float heap number to an intptr.
      54         112 : TNode<UintPtrT> TypedArrayBuiltinsAssembler::CalculateExternalPointer(
      55             :     TNode<UintPtrT> backing_store, TNode<Number> byte_offset) {
      56             :   return Unsigned(
      57         224 :       IntPtrAdd(backing_store, ChangeNonnegativeNumberToUintPtr(byte_offset)));
      58             : }
      59             : 
      60             : // Setup the TypedArray which is under construction.
      61             : //  - Set the length.
      62             : //  - Set the byte_offset.
      63             : //  - Set the byte_length.
      64             : //  - Set EmbedderFields to 0.
      65         112 : void TypedArrayBuiltinsAssembler::SetupTypedArray(TNode<JSTypedArray> holder,
      66             :                                                   TNode<Smi> length,
      67             :                                                   TNode<UintPtrT> byte_offset,
      68             :                                                   TNode<UintPtrT> byte_length) {
      69         112 :   StoreObjectField(holder, JSTypedArray::kLengthOffset, length);
      70             :   StoreObjectFieldNoWriteBarrier(holder, JSArrayBufferView::kByteOffsetOffset,
      71             :                                  byte_offset,
      72         112 :                                  MachineType::PointerRepresentation());
      73             :   StoreObjectFieldNoWriteBarrier(holder, JSArrayBufferView::kByteLengthOffset,
      74             :                                  byte_length,
      75         112 :                                  MachineType::PointerRepresentation());
      76         336 :   for (int offset = JSTypedArray::kHeaderSize;
      77             :        offset < JSTypedArray::kSizeWithEmbedderFields; offset += kTaggedSize) {
      78         448 :     StoreObjectField(holder, offset, SmiConstant(0));
      79             :   }
      80         112 : }
      81             : 
      82             : // Attach an off-heap buffer to a TypedArray.
      83         112 : void TypedArrayBuiltinsAssembler::AttachBuffer(TNode<JSTypedArray> holder,
      84             :                                                TNode<JSArrayBuffer> buffer,
      85             :                                                TNode<Map> map,
      86             :                                                TNode<Smi> length,
      87             :                                                TNode<Number> byte_offset) {
      88         112 :   StoreObjectField(holder, JSArrayBufferView::kBufferOffset, buffer);
      89             : 
      90         224 :   Node* elements = Allocate(FixedTypedArrayBase::kHeaderSize);
      91         112 :   StoreMapNoWriteBarrier(elements, map);
      92         112 :   StoreObjectFieldNoWriteBarrier(elements, FixedArray::kLengthOffset, length);
      93             :   StoreObjectFieldNoWriteBarrier(
      94         224 :       elements, FixedTypedArrayBase::kBasePointerOffset, SmiConstant(0));
      95             : 
      96             :   TNode<UintPtrT> backing_store =
      97         112 :       LoadObjectField<UintPtrT>(buffer, JSArrayBuffer::kBackingStoreOffset);
      98             : 
      99             :   TNode<UintPtrT> external_pointer =
     100         112 :       CalculateExternalPointer(backing_store, byte_offset);
     101             :   StoreObjectFieldNoWriteBarrier(
     102             :       elements, FixedTypedArrayBase::kExternalPointerOffset, external_pointer,
     103         112 :       MachineType::PointerRepresentation());
     104             : 
     105         112 :   StoreObjectField(holder, JSObject::kElementsOffset, elements);
     106         112 : }
     107             : 
     108         448 : TF_BUILTIN(TypedArrayInitializeWithBuffer, TypedArrayBuiltinsAssembler) {
     109          56 :   TNode<JSTypedArray> holder = CAST(Parameter(Descriptor::kHolder));
     110          56 :   TNode<Smi> length = CAST(Parameter(Descriptor::kLength));
     111          56 :   TNode<JSArrayBuffer> buffer = CAST(Parameter(Descriptor::kBuffer));
     112          56 :   TNode<Smi> element_size = CAST(Parameter(Descriptor::kElementSize));
     113          56 :   TNode<Number> byte_offset = CAST(Parameter(Descriptor::kByteOffset));
     114             : 
     115          56 :   TNode<Map> fixed_typed_map = LoadMapForType(holder);
     116             : 
     117             :   // SmiMul returns a heap number in case of Smi overflow.
     118          56 :   TNode<Number> byte_length = SmiMul(length, element_size);
     119             : 
     120             :   SetupTypedArray(holder, length, ChangeNonnegativeNumberToUintPtr(byte_offset),
     121          56 :                   ChangeNonnegativeNumberToUintPtr(byte_length));
     122          56 :   AttachBuffer(holder, buffer, fixed_typed_map, length, byte_offset);
     123         112 :   Return(UndefinedConstant());
     124          56 : }
     125             : 
     126         280 : TF_BUILTIN(TypedArrayInitialize, TypedArrayBuiltinsAssembler) {
     127             :   TNode<JSTypedArray> holder = CAST(Parameter(Descriptor::kHolder));
     128             :   TNode<Smi> length = CAST(Parameter(Descriptor::kLength));
     129          56 :   TNode<Smi> element_size = CAST(Parameter(Descriptor::kElementSize));
     130             :   Node* initialize = Parameter(Descriptor::kInitialize);
     131             :   TNode<JSReceiver> buffer_constructor =
     132             :       CAST(Parameter(Descriptor::kBufferConstructor));
     133             :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
     134             : 
     135             :   CSA_ASSERT(this, TaggedIsPositiveSmi(length));
     136             :   CSA_ASSERT(this, TaggedIsPositiveSmi(element_size));
     137             :   CSA_ASSERT(this, IsBoolean(initialize));
     138             : 
     139          56 :   TNode<Smi> byte_offset = SmiConstant(0);
     140             : 
     141             :   static const int32_t fta_base_data_offset =
     142             :       FixedTypedArrayBase::kDataOffset - kHeapObjectTag;
     143             : 
     144          56 :   Label setup_holder(this), allocate_on_heap(this), aligned(this),
     145          56 :       allocate_elements(this), allocate_off_heap(this),
     146          56 :       allocate_off_heap_custom_constructor(this),
     147          56 :       allocate_off_heap_no_init(this), attach_buffer(this), done(this);
     148             :   TVARIABLE(IntPtrT, var_total_size);
     149             : 
     150             :   // SmiMul returns a heap number in case of Smi overflow.
     151          56 :   TNode<Number> byte_length = SmiMul(length, element_size);
     152             : 
     153          56 :   TNode<Map> fixed_typed_map = LoadMapForType(holder);
     154             : 
     155             :   // If target and new_target for the buffer differ, allocate off-heap.
     156         112 :   TNode<JSFunction> default_constructor = CAST(LoadContextElement(
     157             :       LoadNativeContext(context), Context::ARRAY_BUFFER_FUN_INDEX));
     158             :   GotoIfNot(WordEqual(buffer_constructor, default_constructor),
     159          56 :             &allocate_off_heap_custom_constructor);
     160             : 
     161             :   // For buffers with byte_length over the threshold, allocate off-heap.
     162         112 :   GotoIf(TaggedIsNotSmi(byte_length), &allocate_off_heap);
     163             :   TNode<Smi> smi_byte_length = CAST(byte_length);
     164             :   GotoIf(SmiGreaterThan(smi_byte_length,
     165          56 :                         SmiConstant(V8_TYPED_ARRAY_MAX_SIZE_IN_HEAP)),
     166         112 :          &allocate_off_heap);
     167             :   TNode<IntPtrT> word_byte_length = SmiToIntPtr(smi_byte_length);
     168          56 :   Goto(&allocate_on_heap);
     169             : 
     170          56 :   BIND(&allocate_on_heap);
     171             :   {
     172             :     CSA_ASSERT(this, TaggedIsPositiveSmi(byte_length));
     173             :     // Allocate a new ArrayBuffer and initialize it with empty properties and
     174             :     // elements.
     175         112 :     Node* native_context = LoadNativeContext(context);
     176             :     Node* map =
     177         112 :         LoadContextElement(native_context, Context::ARRAY_BUFFER_MAP_INDEX);
     178         112 :     Node* empty_fixed_array = LoadRoot(RootIndex::kEmptyFixedArray);
     179             : 
     180         112 :     Node* buffer = Allocate(JSArrayBuffer::kSizeWithEmbedderFields);
     181          56 :     StoreMapNoWriteBarrier(buffer, map);
     182             :     StoreObjectFieldNoWriteBarrier(buffer, JSArray::kPropertiesOrHashOffset,
     183          56 :                                    empty_fixed_array);
     184             :     StoreObjectFieldNoWriteBarrier(buffer, JSArray::kElementsOffset,
     185          56 :                                    empty_fixed_array);
     186             :     // Setup the ArrayBuffer.
     187             :     //  - Set BitField to 0.
     188             :     //  - Set IsExternal and IsDetachable bits of BitFieldSlot.
     189             :     //  - Set the byte_length field to byte_length.
     190             :     //  - Set backing_store to null/Smi(0).
     191             :     //  - Set all embedder fields to Smi(0).
     192             :     if (FIELD_SIZE(JSArrayBuffer::kOptionalPaddingOffset) != 0) {
     193             :       DCHECK_EQ(4, FIELD_SIZE(JSArrayBuffer::kOptionalPaddingOffset));
     194             :       StoreObjectFieldNoWriteBarrier(
     195             :           buffer, JSArrayBuffer::kOptionalPaddingOffset, Int32Constant(0),
     196         112 :           MachineRepresentation::kWord32);
     197             :     }
     198             :     int32_t bitfield_value = (1 << JSArrayBuffer::IsExternalBit::kShift) |
     199             :                              (1 << JSArrayBuffer::IsDetachableBit::kShift);
     200             :     StoreObjectFieldNoWriteBarrier(buffer, JSArrayBuffer::kBitFieldOffset,
     201             :                                    Int32Constant(bitfield_value),
     202         112 :                                    MachineRepresentation::kWord32);
     203             : 
     204             :     StoreObjectFieldNoWriteBarrier(buffer, JSArrayBuffer::kByteLengthOffset,
     205             :                                    SmiToIntPtr(CAST(byte_length)),
     206          56 :                                    MachineType::PointerRepresentation());
     207             :     StoreObjectFieldNoWriteBarrier(buffer, JSArrayBuffer::kBackingStoreOffset,
     208         112 :                                    SmiConstant(0));
     209         168 :     for (int offset = JSArrayBuffer::kHeaderSize;
     210             :          offset < JSArrayBuffer::kSizeWithEmbedderFields;
     211             :          offset += kTaggedSize) {
     212         224 :       StoreObjectFieldNoWriteBarrier(buffer, offset, SmiConstant(0));
     213             :     }
     214             : 
     215          56 :     StoreObjectField(holder, JSArrayBufferView::kBufferOffset, buffer);
     216             : 
     217             :     // Check the alignment.
     218             :     // TODO(ishell): remove <Object, Object>
     219             :     GotoIf(WordEqual<Object, Object>(
     220          56 :                SmiMod(element_size, SmiConstant(kObjectAlignment)),
     221         168 :                SmiConstant(0)),
     222          56 :            &aligned);
     223             : 
     224             :     // Fix alignment if needed.
     225             :     DCHECK_EQ(0, FixedTypedArrayBase::kHeaderSize & kObjectAlignmentMask);
     226             :     TNode<IntPtrT> aligned_header_size =
     227          56 :         IntPtrConstant(FixedTypedArrayBase::kHeaderSize + kObjectAlignmentMask);
     228             :     TNode<IntPtrT> size = IntPtrAdd(word_byte_length, aligned_header_size);
     229          56 :     var_total_size = WordAnd(size, IntPtrConstant(~kObjectAlignmentMask));
     230          56 :     Goto(&allocate_elements);
     231             :   }
     232             : 
     233          56 :   BIND(&aligned);
     234             :   {
     235             :     TNode<IntPtrT> header_size =
     236          56 :         IntPtrConstant(FixedTypedArrayBase::kHeaderSize);
     237             :     var_total_size = IntPtrAdd(word_byte_length, header_size);
     238          56 :     Goto(&allocate_elements);
     239             :   }
     240             : 
     241          56 :   BIND(&allocate_elements);
     242             :   {
     243             :     // Allocate a FixedTypedArray and set the length, base pointer and external
     244             :     // pointer.
     245             :     CSA_ASSERT(this, IsRegularHeapObjectSize(var_total_size.value()));
     246             : 
     247             :     Node* elements;
     248             : 
     249         112 :     if (UnalignedLoadSupported(MachineRepresentation::kFloat64) &&
     250          56 :         UnalignedStoreSupported(MachineRepresentation::kFloat64)) {
     251         112 :       elements = AllocateInNewSpace(var_total_size.value());
     252             :     } else {
     253           0 :       elements = AllocateInNewSpace(var_total_size.value(), kDoubleAlignment);
     254             :     }
     255             : 
     256          56 :     StoreMapNoWriteBarrier(elements, fixed_typed_map);
     257          56 :     StoreObjectFieldNoWriteBarrier(elements, FixedArray::kLengthOffset, length);
     258             :     StoreObjectFieldNoWriteBarrier(
     259          56 :         elements, FixedTypedArrayBase::kBasePointerOffset, elements);
     260             :     StoreObjectFieldNoWriteBarrier(elements,
     261             :                                    FixedTypedArrayBase::kExternalPointerOffset,
     262             :                                    IntPtrConstant(fta_base_data_offset),
     263         112 :                                    MachineType::PointerRepresentation());
     264             : 
     265          56 :     StoreObjectField(holder, JSObject::kElementsOffset, elements);
     266             : 
     267         112 :     GotoIf(IsFalse(initialize), &done);
     268             :     // Initialize the backing store by filling it with 0s.
     269             :     Node* backing_store = IntPtrAdd(BitcastTaggedToWord(elements),
     270         168 :                                     IntPtrConstant(fta_base_data_offset));
     271             :     // Call out to memset to perform initialization.
     272         112 :     Node* memset = ExternalConstant(ExternalReference::libc_memset_function());
     273             :     CallCFunction3(MachineType::AnyTagged(), MachineType::Pointer(),
     274             :                    MachineType::IntPtr(), MachineType::UintPtr(), memset,
     275         112 :                    backing_store, IntPtrConstant(0), word_byte_length);
     276          56 :     Goto(&done);
     277             :   }
     278             : 
     279             :   TVARIABLE(JSArrayBuffer, var_buffer);
     280             : 
     281          56 :   BIND(&allocate_off_heap);
     282             :   {
     283         112 :     GotoIf(IsFalse(initialize), &allocate_off_heap_no_init);
     284         112 :     var_buffer = CAST(Construct(context, default_constructor, byte_length));
     285          56 :     Goto(&attach_buffer);
     286             :   }
     287             : 
     288          56 :   BIND(&allocate_off_heap_custom_constructor);
     289             :   {
     290             :     var_buffer =
     291         168 :         CAST(CallStub(CodeFactory::Construct(isolate()), context,
     292             :                       default_constructor, buffer_constructor, Int32Constant(1),
     293             :                       UndefinedConstant(), byte_length));
     294          56 :     Goto(&attach_buffer);
     295             :   }
     296             : 
     297          56 :   BIND(&allocate_off_heap_no_init);
     298             :   {
     299             :     Node* buffer_constructor_noinit = LoadContextElement(
     300         168 :         LoadNativeContext(context), Context::ARRAY_BUFFER_NOINIT_FUN_INDEX);
     301         168 :     var_buffer = CAST(CallJS(CodeFactory::Call(isolate()), context,
     302             :                              buffer_constructor_noinit, UndefinedConstant(),
     303             :                              byte_length));
     304          56 :     Goto(&attach_buffer);
     305             :   }
     306             : 
     307          56 :   BIND(&attach_buffer);
     308             :   {
     309             :     AttachBuffer(holder, var_buffer.value(), fixed_typed_map, length,
     310          56 :                  byte_offset);
     311          56 :     Goto(&done);
     312             :   }
     313             : 
     314          56 :   BIND(&done);
     315             :   SetupTypedArray(holder, length, ChangeNonnegativeNumberToUintPtr(byte_offset),
     316         112 :                   ChangeNonnegativeNumberToUintPtr(byte_length));
     317         168 :   Return(UndefinedConstant());
     318          56 : }
     319             : 
     320             : // ES6 #sec-typedarray-length
     321          56 : void TypedArrayBuiltinsAssembler::ConstructByLength(TNode<Context> context,
     322             :                                                     TNode<JSTypedArray> holder,
     323             :                                                     TNode<Object> length,
     324             :                                                     TNode<Smi> element_size) {
     325             :   // TODO(7881): support larger-than-smi typed array lengths
     326             :   CSA_ASSERT(this, TaggedIsPositiveSmi(element_size));
     327             : 
     328         112 :   Label invalid_length(this, Label::kDeferred), done(this);
     329             : 
     330             :   TNode<Number> converted_length =
     331          56 :       ToInteger_Inline(context, length, CodeStubAssembler::kTruncateMinusZero);
     332             : 
     333             :   // The maximum length of a TypedArray is MaxSmi().
     334             :   // Note: this is not per spec, but rather a constraint of our current
     335             :   // representation (which uses Smis).
     336             :   // TODO(7881): support larger-than-smi typed array lengths
     337         112 :   GotoIf(TaggedIsNotSmi(converted_length), &invalid_length);
     338             :   // The goto above ensures that byte_length is a Smi.
     339          56 :   TNode<Smi> smi_converted_length = CAST(converted_length);
     340         112 :   GotoIf(SmiLessThan(smi_converted_length, SmiConstant(0)), &invalid_length);
     341             : 
     342         112 :   Node* initialize = TrueConstant();
     343         112 :   TNode<JSFunction> default_constructor = CAST(LoadContextElement(
     344             :       LoadNativeContext(context), Context::ARRAY_BUFFER_FUN_INDEX));
     345             :   CallBuiltin(Builtins::kTypedArrayInitialize, context, holder,
     346          56 :               converted_length, element_size, initialize, default_constructor);
     347          56 :   Goto(&done);
     348             : 
     349          56 :   BIND(&invalid_length);
     350             :   {
     351             :     ThrowRangeError(context, MessageTemplate::kInvalidTypedArrayLength,
     352          56 :                     converted_length);
     353             :   }
     354             : 
     355         112 :   BIND(&done);
     356          56 : }
     357             : 
     358             : // ES6 #sec-typedarray-buffer-byteoffset-length
     359          56 : void TypedArrayBuiltinsAssembler::ConstructByArrayBuffer(
     360             :     TNode<Context> context, TNode<JSTypedArray> holder,
     361             :     TNode<JSArrayBuffer> buffer, TNode<Object> byte_offset,
     362             :     TNode<Object> length, TNode<Smi> element_size) {
     363             :   CSA_ASSERT(this, TaggedIsPositiveSmi(element_size));
     364             : 
     365         112 :   VARIABLE(new_byte_length, MachineRepresentation::kTagged, SmiConstant(0));
     366         168 :   VARIABLE(offset, MachineRepresentation::kTagged, SmiConstant(0));
     367             : 
     368          56 :   Label start_offset_error(this, Label::kDeferred),
     369          56 :       byte_length_error(this, Label::kDeferred),
     370          56 :       invalid_offset_error(this, Label::kDeferred);
     371          56 :   Label offset_is_smi(this), offset_not_smi(this, Label::kDeferred),
     372          56 :       check_length(this), call_init(this), invalid_length(this),
     373          56 :       length_undefined(this), length_defined(this), done(this);
     374             : 
     375         112 :   GotoIf(IsUndefined(byte_offset), &check_length);
     376             : 
     377             :   offset.Bind(ToInteger_Inline(context, byte_offset,
     378         112 :                                CodeStubAssembler::kTruncateMinusZero));
     379         168 :   Branch(TaggedIsSmi(offset.value()), &offset_is_smi, &offset_not_smi);
     380             : 
     381             :   // Check that the offset is a multiple of the element size.
     382          56 :   BIND(&offset_is_smi);
     383             :   {
     384          56 :     TNode<Smi> smi_offset = CAST(offset.value());
     385         112 :     GotoIf(SmiEqual(smi_offset, SmiConstant(0)), &check_length);
     386         112 :     GotoIf(SmiLessThan(smi_offset, SmiConstant(0)), &invalid_length);
     387          56 :     TNode<Number> remainder = SmiMod(smi_offset, element_size);
     388             :     // TODO(ishell): remove <Object, Object>
     389         112 :     Branch(WordEqual<Object, Object>(remainder, SmiConstant(0)), &check_length,
     390          56 :            &start_offset_error);
     391             :   }
     392          56 :   BIND(&offset_not_smi);
     393             :   {
     394             :     GotoIf(IsTrue(CallBuiltin(Builtins::kLessThan, context, offset.value(),
     395         168 :                               SmiConstant(0))),
     396         112 :            &invalid_length);
     397             :     Node* remainder =
     398         168 :         CallBuiltin(Builtins::kModulus, context, offset.value(), element_size);
     399             :     // Remainder can be a heap number.
     400             :     Branch(IsTrue(CallBuiltin(Builtins::kEqual, context, remainder,
     401         168 :                               SmiConstant(0))),
     402         112 :            &check_length, &start_offset_error);
     403             :   }
     404             : 
     405          56 :   BIND(&check_length);
     406         112 :   Branch(IsUndefined(length), &length_undefined, &length_defined);
     407             : 
     408          56 :   BIND(&length_undefined);
     409             :   {
     410          56 :     ThrowIfArrayBufferIsDetached(context, buffer, "Construct");
     411             :     TNode<Number> buffer_byte_length = ChangeUintPtrToTagged(
     412          56 :         LoadObjectField<UintPtrT>(buffer, JSArrayBuffer::kByteLengthOffset));
     413             : 
     414             :     Node* remainder = CallBuiltin(Builtins::kModulus, context,
     415         112 :                                   buffer_byte_length, element_size);
     416             :     // Remainder can be a heap number.
     417             :     GotoIf(IsFalse(CallBuiltin(Builtins::kEqual, context, remainder,
     418         168 :                                SmiConstant(0))),
     419         112 :            &byte_length_error);
     420             : 
     421             :     new_byte_length.Bind(CallBuiltin(Builtins::kSubtract, context,
     422         168 :                                      buffer_byte_length, offset.value()));
     423             : 
     424             :     Branch(IsTrue(CallBuiltin(Builtins::kLessThan, context,
     425         168 :                               new_byte_length.value(), SmiConstant(0))),
     426         112 :            &invalid_offset_error, &call_init);
     427             :   }
     428             : 
     429          56 :   BIND(&length_defined);
     430             :   {
     431          56 :     TNode<Smi> new_length = ToSmiIndex(length, context, &invalid_length);
     432          56 :     ThrowIfArrayBufferIsDetached(context, buffer, "Construct");
     433         112 :     new_byte_length.Bind(SmiMul(new_length, element_size));
     434             :     // Reading the byte length must come after the ToIndex operation, which
     435             :     // could cause the buffer to become detached.
     436             :     TNode<Number> buffer_byte_length = ChangeUintPtrToTagged(
     437          56 :         LoadObjectField<UintPtrT>(buffer, JSArrayBuffer::kByteLengthOffset));
     438             : 
     439             :     Node* end = CallBuiltin(Builtins::kAdd, context, offset.value(),
     440         168 :                             new_byte_length.value());
     441             : 
     442             :     Branch(IsTrue(CallBuiltin(Builtins::kGreaterThan, context, end,
     443         112 :                               buffer_byte_length)),
     444         112 :            &invalid_length, &call_init);
     445             :   }
     446             : 
     447          56 :   BIND(&call_init);
     448             :   {
     449             :     TNode<Object> raw_length = CallBuiltin(
     450         112 :         Builtins::kDivide, context, new_byte_length.value(), element_size);
     451             :     // Force the result into a Smi, or throw a range error if it doesn't fit.
     452          56 :     TNode<Smi> new_length = ToSmiIndex(raw_length, context, &invalid_length);
     453             : 
     454             :     CallBuiltin(Builtins::kTypedArrayInitializeWithBuffer, context, holder,
     455         112 :                 new_length, buffer, element_size, offset.value());
     456          56 :     Goto(&done);
     457             :   }
     458             : 
     459          56 :   BIND(&invalid_offset_error);
     460          56 :   { ThrowRangeError(context, MessageTemplate::kInvalidOffset, byte_offset); }
     461             : 
     462          56 :   BIND(&start_offset_error);
     463             :   {
     464         112 :     Node* holder_map = LoadMap(holder);
     465         112 :     Node* problem_string = StringConstant("start offset");
     466             :     CallRuntime(Runtime::kThrowInvalidTypedArrayAlignment, context, holder_map,
     467             :                 problem_string);
     468             : 
     469          56 :     Unreachable();
     470             :   }
     471             : 
     472          56 :   BIND(&byte_length_error);
     473             :   {
     474         112 :     Node* holder_map = LoadMap(holder);
     475         112 :     Node* problem_string = StringConstant("byte length");
     476             :     CallRuntime(Runtime::kThrowInvalidTypedArrayAlignment, context, holder_map,
     477             :                 problem_string);
     478             : 
     479          56 :     Unreachable();
     480             :   }
     481             : 
     482          56 :   BIND(&invalid_length);
     483             :   {
     484          56 :     ThrowRangeError(context, MessageTemplate::kInvalidTypedArrayLength, length);
     485             :   }
     486             : 
     487         112 :   BIND(&done);
     488          56 : }
     489             : 
     490          56 : void TypedArrayBuiltinsAssembler::ConstructByTypedArray(
     491             :     TNode<Context> context, TNode<JSTypedArray> holder,
     492             :     TNode<JSTypedArray> typed_array, TNode<Smi> element_size) {
     493             :   CSA_ASSERT(this, TaggedIsPositiveSmi(element_size));
     494             : 
     495         112 :   TNode<JSFunction> const default_constructor = CAST(LoadContextElement(
     496             :       LoadNativeContext(context), Context::ARRAY_BUFFER_FUN_INDEX));
     497             : 
     498         112 :   Label construct(this), if_detached(this), if_notdetached(this),
     499          56 :       check_for_sab(this), if_buffernotshared(this), check_prototype(this),
     500          56 :       done(this);
     501             :   TVARIABLE(JSReceiver, buffer_constructor, default_constructor);
     502             : 
     503             :   TNode<JSArrayBuffer> source_buffer = LoadObjectField<JSArrayBuffer>(
     504             :       typed_array, JSArrayBufferView::kBufferOffset);
     505         112 :   Branch(IsDetachedBuffer(source_buffer), &if_detached, &if_notdetached);
     506             : 
     507             :   // TODO(petermarshall): Throw on detached typedArray.
     508             :   TVARIABLE(Smi, source_length);
     509          56 :   BIND(&if_detached);
     510          56 :   source_length = SmiConstant(0);
     511          56 :   Goto(&check_for_sab);
     512             : 
     513          56 :   BIND(&if_notdetached);
     514          56 :   source_length = LoadJSTypedArrayLength(typed_array);
     515          56 :   Goto(&check_for_sab);
     516             : 
     517             :   // The spec requires that constructing a typed array using a SAB-backed typed
     518             :   // array use the ArrayBuffer constructor, not the species constructor. See
     519             :   // https://tc39.github.io/ecma262/#sec-typedarray-typedarray.
     520          56 :   BIND(&check_for_sab);
     521             :   TNode<Uint32T> bitfield =
     522             :       LoadObjectField<Uint32T>(source_buffer, JSArrayBuffer::kBitFieldOffset);
     523             :   Branch(IsSetWord32<JSArrayBuffer::IsSharedBit>(bitfield), &construct,
     524          56 :          &if_buffernotshared);
     525             : 
     526          56 :   BIND(&if_buffernotshared);
     527             :   {
     528         112 :     buffer_constructor =
     529             :         SpeciesConstructor(context, source_buffer, default_constructor);
     530             :     // TODO(petermarshall): Throw on detached typedArray.
     531         112 :     GotoIfNot(IsDetachedBuffer(source_buffer), &construct);
     532          56 :     source_length = SmiConstant(0);
     533          56 :     Goto(&construct);
     534             :   }
     535             : 
     536          56 :   BIND(&construct);
     537             :   {
     538             :     ConstructByArrayLike(context, holder, typed_array, source_length.value(),
     539          56 :                          element_size, buffer_constructor.value());
     540          56 :     Goto(&done);
     541             :   }
     542             : 
     543         112 :   BIND(&done);
     544          56 : }
     545             : 
     546        2408 : Node* TypedArrayBuiltinsAssembler::LoadDataPtr(Node* typed_array) {
     547             :   CSA_ASSERT(this, IsJSTypedArray(typed_array));
     548             :   Node* elements = LoadElements(typed_array);
     549             :   CSA_ASSERT(this, IsFixedTypedArray(elements));
     550        4816 :   return LoadFixedTypedArrayBackingStore(CAST(elements));
     551             : }
     552             : 
     553           0 : TNode<BoolT> TypedArrayBuiltinsAssembler::ByteLengthIsValid(
     554             :     TNode<Number> byte_length) {
     555           0 :   Label smi(this), done(this);
     556             :   TVARIABLE(BoolT, is_valid);
     557           0 :   GotoIf(TaggedIsSmi(byte_length), &smi);
     558             : 
     559           0 :   TNode<Float64T> float_value = LoadHeapNumberValue(CAST(byte_length));
     560             :   TNode<Float64T> max_byte_length_double =
     561           0 :       Float64Constant(FixedTypedArrayBase::kMaxByteLength);
     562           0 :   is_valid = Float64LessThanOrEqual(float_value, max_byte_length_double);
     563           0 :   Goto(&done);
     564             : 
     565           0 :   BIND(&smi);
     566             :   TNode<IntPtrT> max_byte_length =
     567           0 :       IntPtrConstant(FixedTypedArrayBase::kMaxByteLength);
     568           0 :   is_valid =
     569             :       UintPtrLessThanOrEqual(SmiUntag(CAST(byte_length)), max_byte_length);
     570           0 :   Goto(&done);
     571             : 
     572           0 :   BIND(&done);
     573           0 :   return is_valid.value();
     574             : }
     575             : 
     576         168 : void TypedArrayBuiltinsAssembler::ConstructByArrayLike(
     577             :     TNode<Context> context, TNode<JSTypedArray> holder,
     578             :     TNode<HeapObject> array_like, TNode<Object> initial_length,
     579             :     TNode<Smi> element_size, TNode<JSReceiver> buffer_constructor) {
     580         336 :   Label invalid_length(this, Label::kDeferred), fill(this), fast_copy(this),
     581         168 :       detached_check(this), done(this);
     582             : 
     583             :   // The caller has looked up length on array_like, which is observable.
     584         168 :   TNode<Smi> length = ToSmiLength(initial_length, context, &invalid_length);
     585             : 
     586         336 :   Node* initialize = FalseConstant();
     587             :   CallBuiltin(Builtins::kTypedArrayInitialize, context, holder, length,
     588         168 :               element_size, initialize, buffer_constructor);
     589             : 
     590         336 :   GotoIf(IsJSTypedArray(array_like), &detached_check);
     591         168 :   Goto(&fill);
     592             : 
     593         168 :   BIND(&detached_check);
     594             :   ThrowIfArrayBufferViewBufferIsDetached(context, CAST(array_like),
     595         168 :                                          "Construct");
     596         168 :   Goto(&fill);
     597             : 
     598         168 :   BIND(&fill);
     599         336 :   GotoIf(SmiEqual(length, SmiConstant(0)), &done);
     600         168 :   TNode<Int32T> holder_kind = LoadElementsKind(holder);
     601         168 :   TNode<Int32T> source_kind = LoadElementsKind(array_like);
     602         336 :   GotoIf(Word32Equal(holder_kind, source_kind), &fast_copy);
     603             : 
     604             :   // Copy using the elements accessor.
     605             :   CallRuntime(Runtime::kTypedArrayCopyElements, context, holder, array_like,
     606             :               length);
     607         168 :   Goto(&done);
     608             : 
     609         168 :   BIND(&fast_copy);
     610             :   {
     611         168 :     Node* holder_data_ptr = LoadDataPtr(holder);
     612         168 :     Node* source_data_ptr = LoadDataPtr(array_like);
     613             : 
     614             :     // Calculate the byte length. We shouldn't be trying to copy if the typed
     615             :     // array was detached.
     616             :     CSA_ASSERT(this, SmiNotEqual(length, SmiConstant(0)));
     617             :     CSA_ASSERT(this, Word32Equal(IsDetachedBuffer(LoadObjectField(
     618             :                                      array_like, JSTypedArray::kBufferOffset)),
     619             :                                  Int32Constant(0)));
     620             : 
     621         168 :     TNode<Number> byte_length = SmiMul(length, element_size);
     622             :     CSA_ASSERT(this, ByteLengthIsValid(byte_length));
     623             :     TNode<UintPtrT> byte_length_intptr =
     624         168 :         ChangeNonnegativeNumberToUintPtr(byte_length);
     625             :     CSA_ASSERT(this, UintPtrLessThanOrEqual(
     626             :                          byte_length_intptr,
     627             :                          IntPtrConstant(FixedTypedArrayBase::kMaxByteLength)));
     628             : 
     629         336 :     Node* memcpy = ExternalConstant(ExternalReference::libc_memcpy_function());
     630             :     CallCFunction3(MachineType::AnyTagged(), MachineType::Pointer(),
     631             :                    MachineType::Pointer(), MachineType::UintPtr(), memcpy,
     632         168 :                    holder_data_ptr, source_data_ptr, byte_length_intptr);
     633         168 :     Goto(&done);
     634             :   }
     635             : 
     636         168 :   BIND(&invalid_length);
     637             :   {
     638             :     ThrowRangeError(context, MessageTemplate::kInvalidTypedArrayLength,
     639         168 :                     initial_length);
     640             :   }
     641             : 
     642         336 :   BIND(&done);
     643         168 : }
     644             : 
     645          56 : void TypedArrayBuiltinsAssembler::ConstructByIterable(
     646             :     TNode<Context> context, TNode<JSTypedArray> holder,
     647             :     TNode<JSReceiver> iterable, TNode<JSReceiver> iterator_fn,
     648             :     TNode<Smi> element_size) {
     649         112 :   Label fast_path(this), slow_path(this), done(this);
     650             :   CSA_ASSERT(this, IsCallable(iterator_fn));
     651             : 
     652             :   TNode<JSArray> array_like =
     653          56 :       CAST(CallBuiltin(Builtins::kIterableToListMayPreserveHoles, context,
     654             :                        iterable, iterator_fn));
     655         112 :   TNode<Object> initial_length = LoadJSArrayLength(array_like);
     656             : 
     657         112 :   TNode<JSFunction> default_constructor = CAST(LoadContextElement(
     658             :       LoadNativeContext(context), Context::ARRAY_BUFFER_FUN_INDEX));
     659             :   ConstructByArrayLike(context, holder, array_like, initial_length,
     660         112 :                        element_size, default_constructor);
     661          56 : }
     662             : 
     663         224 : TF_BUILTIN(TypedArrayBaseConstructor, TypedArrayBuiltinsAssembler) {
     664             :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
     665             :   ThrowTypeError(context, MessageTemplate::kConstructAbstractClass,
     666          56 :                  "TypedArray");
     667          56 : }
     668             : 
     669             : // ES #sec-typedarray-constructors
     670         280 : TF_BUILTIN(CreateTypedArray, TypedArrayBuiltinsAssembler) {
     671             :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
     672             :   TNode<JSFunction> target = CAST(Parameter(Descriptor::kTarget));
     673             :   TNode<JSReceiver> new_target = CAST(Parameter(Descriptor::kNewTarget));
     674             :   TNode<Object> arg1 = CAST(Parameter(Descriptor::kArg1));
     675          56 :   TNode<Object> arg2 = CAST(Parameter(Descriptor::kArg2));
     676          56 :   TNode<Object> arg3 = CAST(Parameter(Descriptor::kArg3));
     677             : 
     678             :   CSA_ASSERT(this, IsConstructor(target));
     679             :   CSA_ASSERT(this, IsJSReceiver(new_target));
     680             : 
     681          56 :   Label if_arg1isbuffer(this), if_arg1istypedarray(this),
     682          56 :       if_arg1isreceiver(this), if_arg1isnumber(this), return_result(this);
     683             : 
     684             :   ConstructorBuiltinsAssembler constructor_assembler(this->state());
     685          56 :   TNode<JSTypedArray> result = CAST(
     686             :       constructor_assembler.EmitFastNewObject(context, target, new_target));
     687             :   // We need to set the byte_offset / byte_length to some sane values
     688             :   // to keep the heap verifier happy.
     689             :   // TODO(bmeurer): Fix this initialization to not use EmitFastNewObject,
     690             :   // which causes the problem, since it puts Undefined into all slots of
     691             :   // the object even though that doesn't make any sense for these fields.
     692             :   StoreObjectFieldNoWriteBarrier(result, JSTypedArray::kByteOffsetOffset,
     693             :                                  UintPtrConstant(0),
     694          56 :                                  MachineType::PointerRepresentation());
     695             :   StoreObjectFieldNoWriteBarrier(result, JSTypedArray::kByteLengthOffset,
     696             :                                  UintPtrConstant(0),
     697          56 :                                  MachineType::PointerRepresentation());
     698             : 
     699             :   TNode<Smi> element_size =
     700         168 :       SmiTag(GetTypedArrayElementSize(LoadElementsKind(result)));
     701             : 
     702         112 :   GotoIf(TaggedIsSmi(arg1), &if_arg1isnumber);
     703             :   TNode<HeapObject> arg1_heap_object = UncheckedCast<HeapObject>(arg1);
     704         112 :   GotoIf(IsJSArrayBuffer(arg1_heap_object), &if_arg1isbuffer);
     705         112 :   GotoIf(IsJSTypedArray(arg1_heap_object), &if_arg1istypedarray);
     706         112 :   GotoIf(IsJSReceiver(arg1_heap_object), &if_arg1isreceiver);
     707          56 :   Goto(&if_arg1isnumber);
     708             : 
     709             :   // https://tc39.github.io/ecma262/#sec-typedarray-buffer-byteoffset-length
     710          56 :   BIND(&if_arg1isbuffer);
     711             :   {
     712             :     ConstructByArrayBuffer(context, result, CAST(arg1), arg2, arg3,
     713          56 :                            element_size);
     714          56 :     Goto(&return_result);
     715             :   }
     716             : 
     717             :   // https://tc39.github.io/ecma262/#sec-typedarray-typedarray
     718          56 :   BIND(&if_arg1istypedarray);
     719             :   {
     720          56 :     TNode<JSTypedArray> typed_array = CAST(arg1_heap_object);
     721          56 :     ConstructByTypedArray(context, result, typed_array, element_size);
     722          56 :     Goto(&return_result);
     723             :   }
     724             : 
     725             :   // https://tc39.github.io/ecma262/#sec-typedarray-object
     726          56 :   BIND(&if_arg1isreceiver);
     727             :   {
     728          56 :     Label if_iteratorundefined(this), if_iteratornotcallable(this);
     729             :     // Get iterator symbol
     730         112 :     TNode<Object> iteratorFn = CAST(GetMethod(
     731             :         context, arg1_heap_object, isolate()->factory()->iterator_symbol(),
     732             :         &if_iteratorundefined));
     733         112 :     GotoIf(TaggedIsSmi(iteratorFn), &if_iteratornotcallable);
     734         112 :     GotoIfNot(IsCallable(CAST(iteratorFn)), &if_iteratornotcallable);
     735             : 
     736             :     ConstructByIterable(context, result, CAST(arg1_heap_object),
     737          56 :                         CAST(iteratorFn), element_size);
     738          56 :     Goto(&return_result);
     739             : 
     740          56 :     BIND(&if_iteratorundefined);
     741             :     {
     742          56 :       TNode<HeapObject> array_like = arg1_heap_object;
     743             :       TNode<Object> initial_length =
     744         112 :           GetProperty(context, arg1, LengthStringConstant());
     745             : 
     746         112 :       TNode<JSFunction> default_constructor = CAST(LoadContextElement(
     747             :           LoadNativeContext(context), Context::ARRAY_BUFFER_FUN_INDEX));
     748             :       ConstructByArrayLike(context, result, array_like, initial_length,
     749          56 :                            element_size, default_constructor);
     750          56 :       Goto(&return_result);
     751             :     }
     752             : 
     753          56 :     BIND(&if_iteratornotcallable);
     754         112 :     { ThrowTypeError(context, MessageTemplate::kIteratorSymbolNonCallable); }
     755             :   }
     756             : 
     757             :   // The first argument was a number or fell through and is treated as
     758             :   // a number. https://tc39.github.io/ecma262/#sec-typedarray-length
     759          56 :   BIND(&if_arg1isnumber);
     760             :   {
     761          56 :     ConstructByLength(context, result, arg1, element_size);
     762          56 :     Goto(&return_result);
     763             :   }
     764             : 
     765          56 :   BIND(&return_result);
     766         112 :   Return(result);
     767          56 : }
     768             : 
     769             : // ES #sec-typedarray-constructors
     770         224 : TF_BUILTIN(TypedArrayConstructor, TypedArrayBuiltinsAssembler) {
     771             :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
     772             :   TNode<JSFunction> target = CAST(Parameter(Descriptor::kJSTarget));
     773             :   TNode<Object> new_target = CAST(Parameter(Descriptor::kJSNewTarget));
     774             :   Node* argc =
     775         112 :       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
     776          56 :   CodeStubArguments args(this, argc);
     777         112 :   Node* arg1 = args.GetOptionalArgumentValue(0);
     778         112 :   Node* arg2 = args.GetOptionalArgumentValue(1);
     779         112 :   Node* arg3 = args.GetOptionalArgumentValue(2);
     780             : 
     781             :   // If NewTarget is undefined, throw a TypeError exception.
     782             :   // All the TypedArray constructors have this as the first step:
     783             :   // https://tc39.github.io/ecma262/#sec-typedarray-constructors
     784             :   Label throwtypeerror(this, Label::kDeferred);
     785         112 :   GotoIf(IsUndefined(new_target), &throwtypeerror);
     786             : 
     787             :   Node* result = CallBuiltin(Builtins::kCreateTypedArray, context, target,
     788         112 :                              new_target, arg1, arg2, arg3);
     789          56 :   args.PopAndReturn(result);
     790             : 
     791          56 :   BIND(&throwtypeerror);
     792             :   {
     793             :     TNode<String> name =
     794             :         CAST(CallRuntime(Runtime::kGetFunctionName, context, target));
     795          56 :     ThrowTypeError(context, MessageTemplate::kConstructorNotFunction, name);
     796          56 :   }
     797          56 : }
     798             : 
     799             : // ES6 #sec-get-%typedarray%.prototype.bytelength
     800         224 : TF_BUILTIN(TypedArrayPrototypeByteLength, TypedArrayBuiltinsAssembler) {
     801             :   const char* const kMethodName = "get TypedArray.prototype.byteLength";
     802             :   Node* context = Parameter(Descriptor::kContext);
     803             :   Node* receiver = Parameter(Descriptor::kReceiver);
     804             : 
     805             :   // Check if the {receiver} is actually a JSTypedArray.
     806          56 :   ThrowIfNotInstanceType(context, receiver, JS_TYPED_ARRAY_TYPE, kMethodName);
     807             : 
     808             :   // Default to zero if the {receiver}s buffer was detached.
     809             :   TNode<JSArrayBuffer> receiver_buffer =
     810          56 :       LoadJSArrayBufferViewBuffer(CAST(receiver));
     811             :   TNode<UintPtrT> byte_length = Select<UintPtrT>(
     812          56 :       IsDetachedBuffer(receiver_buffer), [=] { return UintPtrConstant(0); },
     813         224 :       [=] { return LoadJSArrayBufferViewByteLength(CAST(receiver)); });
     814         112 :   Return(ChangeUintPtrToTagged(byte_length));
     815          56 : }
     816             : 
     817             : // ES6 #sec-get-%typedarray%.prototype.byteoffset
     818         224 : TF_BUILTIN(TypedArrayPrototypeByteOffset, TypedArrayBuiltinsAssembler) {
     819             :   const char* const kMethodName = "get TypedArray.prototype.byteOffset";
     820             :   Node* context = Parameter(Descriptor::kContext);
     821             :   Node* receiver = Parameter(Descriptor::kReceiver);
     822             : 
     823             :   // Check if the {receiver} is actually a JSTypedArray.
     824          56 :   ThrowIfNotInstanceType(context, receiver, JS_TYPED_ARRAY_TYPE, kMethodName);
     825             : 
     826             :   // Default to zero if the {receiver}s buffer was detached.
     827             :   TNode<JSArrayBuffer> receiver_buffer =
     828          56 :       LoadJSArrayBufferViewBuffer(CAST(receiver));
     829             :   TNode<UintPtrT> byte_offset = Select<UintPtrT>(
     830          56 :       IsDetachedBuffer(receiver_buffer), [=] { return UintPtrConstant(0); },
     831         224 :       [=] { return LoadJSArrayBufferViewByteOffset(CAST(receiver)); });
     832         112 :   Return(ChangeUintPtrToTagged(byte_offset));
     833          56 : }
     834             : 
     835             : // ES6 #sec-get-%typedarray%.prototype.length
     836         224 : TF_BUILTIN(TypedArrayPrototypeLength, TypedArrayBuiltinsAssembler) {
     837             :   const char* const kMethodName = "get TypedArray.prototype.length";
     838             :   Node* context = Parameter(Descriptor::kContext);
     839             :   Node* receiver = Parameter(Descriptor::kReceiver);
     840             : 
     841             :   // Check if the {receiver} is actually a JSTypedArray.
     842          56 :   ThrowIfNotInstanceType(context, receiver, JS_TYPED_ARRAY_TYPE, kMethodName);
     843             : 
     844             :   // Default to zero if the {receiver}s buffer was detached.
     845             :   TNode<JSArrayBuffer> receiver_buffer =
     846          56 :       LoadJSArrayBufferViewBuffer(CAST(receiver));
     847             :   TNode<Smi> length = Select<Smi>(
     848          56 :       IsDetachedBuffer(receiver_buffer), [=] { return SmiConstant(0); },
     849         224 :       [=] { return LoadJSTypedArrayLength(CAST(receiver)); });
     850          56 :   Return(length);
     851          56 : }
     852             : 
     853         112 : TNode<Word32T> TypedArrayBuiltinsAssembler::IsUint8ElementsKind(
     854             :     TNode<Word32T> kind) {
     855         224 :   return Word32Or(Word32Equal(kind, Int32Constant(UINT8_ELEMENTS)),
     856         560 :                   Word32Equal(kind, Int32Constant(UINT8_CLAMPED_ELEMENTS)));
     857             : }
     858             : 
     859         280 : TNode<Word32T> TypedArrayBuiltinsAssembler::IsBigInt64ElementsKind(
     860             :     TNode<Word32T> kind) {
     861         560 :   return Word32Or(Word32Equal(kind, Int32Constant(BIGINT64_ELEMENTS)),
     862        1400 :                   Word32Equal(kind, Int32Constant(BIGUINT64_ELEMENTS)));
     863             : }
     864             : 
     865         280 : TNode<IntPtrT> TypedArrayBuiltinsAssembler::GetTypedArrayElementSize(
     866             :     TNode<Word32T> elements_kind) {
     867         280 :   TVARIABLE(IntPtrT, element_size);
     868             : 
     869             :   DispatchTypedArrayByElementsKind(
     870             :       elements_kind,
     871        3080 :       [&](ElementsKind el_kind, int size, int typed_array_fun_index) {
     872        3080 :         element_size = IntPtrConstant(size);
     873        3640 :       });
     874             : 
     875         280 :   return element_size.value();
     876             : }
     877             : 
     878         224 : TNode<JSFunction> TypedArrayBuiltinsAssembler::GetDefaultConstructor(
     879             :     TNode<Context> context, TNode<JSTypedArray> exemplar) {
     880         224 :   TVARIABLE(IntPtrT, context_slot);
     881         448 :   TNode<Word32T> elements_kind = LoadElementsKind(exemplar);
     882             : 
     883             :   DispatchTypedArrayByElementsKind(
     884             :       elements_kind,
     885        2464 :       [&](ElementsKind el_kind, int size, int typed_array_function_index) {
     886        2464 :         context_slot = IntPtrConstant(typed_array_function_index);
     887        2912 :       });
     888             : 
     889         672 :   return CAST(
     890             :       LoadContextElement(LoadNativeContext(context), context_slot.value()));
     891             : }
     892             : 
     893             : template <class... TArgs>
     894         224 : TNode<JSTypedArray> TypedArrayBuiltinsAssembler::TypedArraySpeciesCreate(
     895             :     const char* method_name, TNode<Context> context,
     896             :     TNode<JSTypedArray> exemplar, TArgs... args) {
     897         224 :   TVARIABLE(JSTypedArray, var_new_typed_array);
     898         224 :   Label slow(this, Label::kDeferred), done(this);
     899             : 
     900             :   // Let defaultConstructor be the intrinsic object listed in column one of
     901             :   // Table 52 for exemplar.[[TypedArrayName]].
     902             :   TNode<JSFunction> default_constructor =
     903         224 :       GetDefaultConstructor(context, exemplar);
     904             : 
     905         224 :   TNode<Map> map = LoadMap(exemplar);
     906         448 :   GotoIfNot(IsPrototypeTypedArrayPrototype(context, map), &slow);
     907         448 :   GotoIf(IsTypedArraySpeciesProtectorCellInvalid(), &slow);
     908             :   {
     909             :     const size_t argc = sizeof...(args);
     910             :     static_assert(argc >= 1 && argc <= 3,
     911             :                   "TypedArraySpeciesCreate called with unexpected arguments");
     912             :     TNode<Object> arg_list[argc] = {args...};
     913         224 :     TNode<Object> arg0 = argc < 1 ? UndefinedConstant() : arg_list[0];
     914         392 :     TNode<Object> arg1 = argc < 2 ? UndefinedConstant() : arg_list[1];
     915         392 :     TNode<Object> arg2 = argc < 3 ? UndefinedConstant() : arg_list[2];
     916         448 :     var_new_typed_array = UncheckedCast<JSTypedArray>(
     917             :         CallBuiltin(Builtins::kCreateTypedArray, context, default_constructor,
     918             :                     default_constructor, arg0, arg1, arg2));
     919             : #ifdef DEBUG
     920             :     // It is assumed that the CreateTypedArray builtin does not produce a
     921             :     // typed array that fails ValidateTypedArray.
     922             :     TNode<JSArrayBuffer> buffer =
     923             :         LoadJSArrayBufferViewBuffer(var_new_typed_array.value());
     924             :     CSA_ASSERT(this, Word32BinaryNot(IsDetachedBuffer(buffer)));
     925             : #endif  // DEBUG
     926         224 :     Goto(&done);
     927             :   }
     928         224 :   BIND(&slow);
     929             :   {
     930             :     // Let constructor be ? SpeciesConstructor(exemplar, defaultConstructor).
     931             :     TNode<JSReceiver> constructor =
     932         224 :         SpeciesConstructor(context, exemplar, default_constructor);
     933             : 
     934             :     // Let newTypedArray be ? Construct(constructor, argumentList).
     935         224 :     TNode<JSReceiver> new_object = Construct(context, constructor, args...);
     936             : 
     937             :     // Perform ? ValidateTypedArray(newTypedArray).
     938         448 :     var_new_typed_array = ValidateTypedArray(context, new_object, method_name);
     939         224 :     Goto(&done);
     940             :   }
     941             : 
     942         224 :   BIND(&done);
     943         224 :   return var_new_typed_array.value();
     944             : }
     945             : 
     946             : TNode<JSTypedArray>
     947         168 : TypedArrayBuiltinsAssembler::TypedArraySpeciesCreateByLength(
     948             :     TNode<Context> context, TNode<JSTypedArray> exemplar, TNode<Smi> len,
     949             :     const char* method_name) {
     950             :   CSA_ASSERT(this, TaggedIsPositiveSmi(len));
     951             : 
     952             :   TNode<JSTypedArray> new_typed_array =
     953         168 :       TypedArraySpeciesCreate(method_name, context, exemplar, len);
     954             : 
     955         168 :   ThrowIfLengthLessThan(context, new_typed_array, len);
     956         168 :   return new_typed_array;
     957             : }
     958             : 
     959         112 : TNode<JSTypedArray> TypedArrayBuiltinsAssembler::TypedArrayCreateByLength(
     960             :     TNode<Context> context, TNode<Object> constructor, TNode<Smi> len,
     961             :     const char* method_name) {
     962             :   CSA_ASSERT(this, TaggedIsPositiveSmi(len));
     963             : 
     964             :   // Let newTypedArray be ? Construct(constructor, argumentList).
     965         224 :   TNode<Object> new_object = CAST(ConstructJS(CodeFactory::Construct(isolate()),
     966             :                                               context, constructor, len));
     967             : 
     968             :   // Perform ? ValidateTypedArray(newTypedArray).
     969             :   TNode<JSTypedArray> new_typed_array =
     970         112 :       ValidateTypedArray(context, new_object, method_name);
     971             : 
     972         112 :   ThrowIfLengthLessThan(context, new_typed_array, len);
     973         112 :   return new_typed_array;
     974             : }
     975             : 
     976         280 : void TypedArrayBuiltinsAssembler::ThrowIfLengthLessThan(
     977             :     TNode<Context> context, TNode<JSTypedArray> typed_array,
     978             :     TNode<Smi> min_length) {
     979             :   // If typed_array.[[ArrayLength]] < min_length, throw a TypeError exception.
     980         280 :   Label if_length_is_not_short(this);
     981         280 :   TNode<Smi> new_length = LoadJSTypedArrayLength(typed_array);
     982         560 :   GotoIfNot(SmiLessThan(new_length, min_length), &if_length_is_not_short);
     983         280 :   ThrowTypeError(context, MessageTemplate::kTypedArrayTooShort);
     984             : 
     985         280 :   BIND(&if_length_is_not_short);
     986         280 : }
     987             : 
     988          56 : TNode<JSArrayBuffer> TypedArrayBuiltinsAssembler::GetBuffer(
     989             :     TNode<Context> context, TNode<JSTypedArray> array) {
     990         112 :   Label call_runtime(this), done(this);
     991             :   TVARIABLE(Object, var_result);
     992             : 
     993          56 :   TNode<Object> buffer = LoadObjectField(array, JSTypedArray::kBufferOffset);
     994         112 :   GotoIf(IsDetachedBuffer(buffer), &call_runtime);
     995             :   TNode<UintPtrT> backing_store = LoadObjectField<UintPtrT>(
     996             :       CAST(buffer), JSArrayBuffer::kBackingStoreOffset);
     997         168 :   GotoIf(WordEqual(backing_store, IntPtrConstant(0)), &call_runtime);
     998             :   var_result = buffer;
     999          56 :   Goto(&done);
    1000             : 
    1001          56 :   BIND(&call_runtime);
    1002             :   {
    1003             :     var_result = CallRuntime(Runtime::kTypedArrayGetBuffer, context, array);
    1004          56 :     Goto(&done);
    1005             :   }
    1006             : 
    1007          56 :   BIND(&done);
    1008          56 :   return CAST(var_result.value());
    1009             : }
    1010             : 
    1011         616 : TNode<JSTypedArray> TypedArrayBuiltinsAssembler::ValidateTypedArray(
    1012             :     TNode<Context> context, TNode<Object> obj, const char* method_name) {
    1013             :   // If it is not a typed array, throw
    1014         616 :   ThrowIfNotInstanceType(context, obj, JS_TYPED_ARRAY_TYPE, method_name);
    1015             : 
    1016             :   // If the typed array's buffer is detached, throw
    1017         616 :   ThrowIfArrayBufferViewBufferIsDetached(context, CAST(obj), method_name);
    1018             : 
    1019         616 :   return CAST(obj);
    1020             : }
    1021             : 
    1022          56 : void TypedArrayBuiltinsAssembler::SetTypedArraySource(
    1023             :     TNode<Context> context, TNode<JSTypedArray> source,
    1024             :     TNode<JSTypedArray> target, TNode<IntPtrT> offset, Label* call_runtime,
    1025             :     Label* if_source_too_large) {
    1026             :   CSA_ASSERT(this, Word32BinaryNot(IsDetachedBuffer(
    1027             :                        LoadObjectField(source, JSTypedArray::kBufferOffset))));
    1028             :   CSA_ASSERT(this, Word32BinaryNot(IsDetachedBuffer(
    1029             :                        LoadObjectField(target, JSTypedArray::kBufferOffset))));
    1030             :   CSA_ASSERT(this, IntPtrGreaterThanOrEqual(offset, IntPtrConstant(0)));
    1031             :   CSA_ASSERT(this,
    1032             :              IntPtrLessThanOrEqual(offset, IntPtrConstant(Smi::kMaxValue)));
    1033             : 
    1034             :   // Check for possible range errors.
    1035             : 
    1036         112 :   TNode<IntPtrT> source_length = SmiUntag(LoadJSTypedArrayLength(source));
    1037         112 :   TNode<IntPtrT> target_length = SmiUntag(LoadJSTypedArrayLength(target));
    1038          56 :   TNode<IntPtrT> required_target_length = IntPtrAdd(source_length, offset);
    1039             : 
    1040          56 :   GotoIf(IntPtrGreaterThan(required_target_length, target_length),
    1041         112 :          if_source_too_large);
    1042             : 
    1043             :   // Grab pointers and byte lengths we need later on.
    1044             : 
    1045          56 :   TNode<IntPtrT> target_data_ptr = UncheckedCast<IntPtrT>(LoadDataPtr(target));
    1046          56 :   TNode<IntPtrT> source_data_ptr = UncheckedCast<IntPtrT>(LoadDataPtr(source));
    1047             : 
    1048         112 :   TNode<Word32T> source_el_kind = LoadElementsKind(source);
    1049         112 :   TNode<Word32T> target_el_kind = LoadElementsKind(target);
    1050             : 
    1051          56 :   TNode<IntPtrT> source_el_size = GetTypedArrayElementSize(source_el_kind);
    1052          56 :   TNode<IntPtrT> target_el_size = GetTypedArrayElementSize(target_el_kind);
    1053             : 
    1054             :   // A note on byte lengths: both source- and target byte lengths must be valid,
    1055             :   // i.e. it must be possible to allocate an array of the given length. That
    1056             :   // means we're safe from overflows in the following multiplication.
    1057          56 :   TNode<IntPtrT> source_byte_length = IntPtrMul(source_length, source_el_size);
    1058             :   CSA_ASSERT(this,
    1059             :              UintPtrGreaterThanOrEqual(source_byte_length, IntPtrConstant(0)));
    1060             : 
    1061          56 :   Label call_memmove(this), fast_c_call(this), out(this), exception(this);
    1062             : 
    1063             :   // A fast memmove call can be used when the source and target types are are
    1064             :   // the same or either Uint8 or Uint8Clamped.
    1065         112 :   GotoIf(Word32Equal(source_el_kind, target_el_kind), &call_memmove);
    1066         112 :   GotoIfNot(IsUint8ElementsKind(source_el_kind), &fast_c_call);
    1067         112 :   Branch(IsUint8ElementsKind(target_el_kind), &call_memmove, &fast_c_call);
    1068             : 
    1069          56 :   BIND(&call_memmove);
    1070             :   {
    1071             :     TNode<IntPtrT> target_start =
    1072          56 :         IntPtrAdd(target_data_ptr, IntPtrMul(offset, target_el_size));
    1073          56 :     CallCMemmove(target_start, source_data_ptr, source_byte_length);
    1074          56 :     Goto(&out);
    1075             :   }
    1076             : 
    1077          56 :   BIND(&fast_c_call);
    1078             :   {
    1079             :     CSA_ASSERT(
    1080             :         this, UintPtrGreaterThanOrEqual(
    1081             :                   IntPtrMul(target_length, target_el_size), IntPtrConstant(0)));
    1082             : 
    1083             :     GotoIf(Word32NotEqual(IsBigInt64ElementsKind(source_el_kind),
    1084         168 :                           IsBigInt64ElementsKind(target_el_kind)),
    1085         112 :            &exception);
    1086             : 
    1087         112 :     TNode<IntPtrT> source_length = SmiUntag(LoadJSTypedArrayLength(source));
    1088             :     CallCCopyTypedArrayElementsToTypedArray(source, target, source_length,
    1089          56 :                                             offset);
    1090          56 :     Goto(&out);
    1091             :   }
    1092             : 
    1093          56 :   BIND(&exception);
    1094          56 :   ThrowTypeError(context, MessageTemplate::kBigIntMixedTypes);
    1095             : 
    1096         112 :   BIND(&out);
    1097          56 : }
    1098             : 
    1099          56 : void TypedArrayBuiltinsAssembler::SetJSArraySource(
    1100             :     TNode<Context> context, TNode<JSArray> source, TNode<JSTypedArray> target,
    1101             :     TNode<IntPtrT> offset, Label* call_runtime, Label* if_source_too_large) {
    1102             :   CSA_ASSERT(this, IsFastJSArray(source, context));
    1103             :   CSA_ASSERT(this, IntPtrGreaterThanOrEqual(offset, IntPtrConstant(0)));
    1104             :   CSA_ASSERT(this,
    1105             :              IntPtrLessThanOrEqual(offset, IntPtrConstant(Smi::kMaxValue)));
    1106             : 
    1107         112 :   TNode<IntPtrT> source_length = SmiUntag(LoadFastJSArrayLength(source));
    1108         112 :   TNode<IntPtrT> target_length = SmiUntag(LoadJSTypedArrayLength(target));
    1109             : 
    1110             :   // Maybe out of bounds?
    1111         112 :   GotoIf(IntPtrGreaterThan(IntPtrAdd(source_length, offset), target_length),
    1112         112 :          if_source_too_large);
    1113             : 
    1114             :   // Nothing to do if {source} is empty.
    1115          56 :   Label out(this), fast_c_call(this);
    1116         168 :   GotoIf(IntPtrEqual(source_length, IntPtrConstant(0)), &out);
    1117             : 
    1118             :   // Dispatch based on the source elements kind.
    1119             :   {
    1120             :     // These are the supported elements kinds in TryCopyElementsFastNumber.
    1121             :     int32_t values[] = {
    1122             :         PACKED_SMI_ELEMENTS, HOLEY_SMI_ELEMENTS, PACKED_DOUBLE_ELEMENTS,
    1123             :         HOLEY_DOUBLE_ELEMENTS,
    1124          56 :     };
    1125             :     Label* labels[] = {
    1126             :         &fast_c_call, &fast_c_call, &fast_c_call, &fast_c_call,
    1127          56 :     };
    1128             :     STATIC_ASSERT(arraysize(values) == arraysize(labels));
    1129             : 
    1130          56 :     TNode<Int32T> source_elements_kind = LoadElementsKind(source);
    1131             :     Switch(source_elements_kind, call_runtime, values, labels,
    1132          56 :            arraysize(values));
    1133             :   }
    1134             : 
    1135          56 :   BIND(&fast_c_call);
    1136         168 :   GotoIf(IsBigInt64ElementsKind(LoadElementsKind(target)), call_runtime);
    1137             :   CallCCopyFastNumberJSArrayElementsToTypedArray(context, source, target,
    1138          56 :                                                  source_length, offset);
    1139          56 :   Goto(&out);
    1140         112 :   BIND(&out);
    1141          56 : }
    1142             : 
    1143         112 : void TypedArrayBuiltinsAssembler::CallCMemmove(TNode<IntPtrT> dest_ptr,
    1144             :                                                TNode<IntPtrT> src_ptr,
    1145             :                                                TNode<IntPtrT> byte_length) {
    1146             :   TNode<ExternalReference> memmove =
    1147         112 :       ExternalConstant(ExternalReference::libc_memmove_function());
    1148             :   CallCFunction3(MachineType::AnyTagged(), MachineType::Pointer(),
    1149             :                  MachineType::Pointer(), MachineType::UintPtr(), memmove,
    1150         112 :                  dest_ptr, src_ptr, byte_length);
    1151         112 : }
    1152             : 
    1153          56 : void TypedArrayBuiltinsAssembler::
    1154             :     CallCCopyFastNumberJSArrayElementsToTypedArray(TNode<Context> context,
    1155             :                                                    TNode<JSArray> source,
    1156             :                                                    TNode<JSTypedArray> dest,
    1157             :                                                    TNode<IntPtrT> source_length,
    1158             :                                                    TNode<IntPtrT> offset) {
    1159             :   CSA_ASSERT(this,
    1160             :              Word32BinaryNot(IsBigInt64ElementsKind(LoadElementsKind(dest))));
    1161             :   TNode<ExternalReference> f = ExternalConstant(
    1162          56 :       ExternalReference::copy_fast_number_jsarray_elements_to_typed_array());
    1163             :   CallCFunction5(MachineType::AnyTagged(), MachineType::AnyTagged(),
    1164             :                  MachineType::AnyTagged(), MachineType::AnyTagged(),
    1165             :                  MachineType::UintPtr(), MachineType::UintPtr(), f, context,
    1166          56 :                  source, dest, source_length, offset);
    1167          56 : }
    1168             : 
    1169          56 : void TypedArrayBuiltinsAssembler::CallCCopyTypedArrayElementsToTypedArray(
    1170             :     TNode<JSTypedArray> source, TNode<JSTypedArray> dest,
    1171             :     TNode<IntPtrT> source_length, TNode<IntPtrT> offset) {
    1172             :   TNode<ExternalReference> f = ExternalConstant(
    1173          56 :       ExternalReference::copy_typed_array_elements_to_typed_array());
    1174             :   CallCFunction4(MachineType::AnyTagged(), MachineType::AnyTagged(),
    1175             :                  MachineType::AnyTagged(), MachineType::UintPtr(),
    1176             :                  MachineType::UintPtr(), f, source, dest, source_length,
    1177          56 :                  offset);
    1178          56 : }
    1179             : 
    1180          56 : void TypedArrayBuiltinsAssembler::CallCCopyTypedArrayElementsSlice(
    1181             :     TNode<JSTypedArray> source, TNode<JSTypedArray> dest, TNode<IntPtrT> start,
    1182             :     TNode<IntPtrT> end) {
    1183             :   TNode<ExternalReference> f =
    1184          56 :       ExternalConstant(ExternalReference::copy_typed_array_elements_slice());
    1185             :   CallCFunction4(MachineType::AnyTagged(), MachineType::AnyTagged(),
    1186             :                  MachineType::AnyTagged(), MachineType::UintPtr(),
    1187          56 :                  MachineType::UintPtr(), f, source, dest, start, end);
    1188          56 : }
    1189             : 
    1190         784 : void TypedArrayBuiltinsAssembler::DispatchTypedArrayByElementsKind(
    1191             :     TNode<Word32T> elements_kind, const TypedArraySwitchCase& case_function) {
    1192        1568 :   Label next(this), if_unknown_type(this, Label::kDeferred);
    1193             : 
    1194             :   int32_t elements_kinds[] = {
    1195             : #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) TYPE##_ELEMENTS,
    1196             :       TYPED_ARRAYS(TYPED_ARRAY_CASE)
    1197             : #undef TYPED_ARRAY_CASE
    1198         784 :   };
    1199             : 
    1200             : #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) Label if_##type##array(this);
    1201         784 :   TYPED_ARRAYS(TYPED_ARRAY_CASE)
    1202             : #undef TYPED_ARRAY_CASE
    1203             : 
    1204             :   Label* elements_kind_labels[] = {
    1205             : #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) &if_##type##array,
    1206             :       TYPED_ARRAYS(TYPED_ARRAY_CASE)
    1207             : #undef TYPED_ARRAY_CASE
    1208         784 :   };
    1209             :   STATIC_ASSERT(arraysize(elements_kinds) == arraysize(elements_kind_labels));
    1210             : 
    1211             :   Switch(elements_kind, &if_unknown_type, elements_kinds, elements_kind_labels,
    1212         784 :          arraysize(elements_kinds));
    1213             : 
    1214             : #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype)   \
    1215             :   BIND(&if_##type##array);                          \
    1216             :   {                                                 \
    1217             :     case_function(TYPE##_ELEMENTS, sizeof(ctype),   \
    1218             :                   Context::TYPE##_ARRAY_FUN_INDEX); \
    1219             :     Goto(&next);                                    \
    1220             :   }
    1221         784 :   TYPED_ARRAYS(TYPED_ARRAY_CASE)
    1222             : #undef TYPED_ARRAY_CASE
    1223             : 
    1224         784 :   BIND(&if_unknown_type);
    1225         784 :   Unreachable();
    1226             : 
    1227        1568 :   BIND(&next);
    1228         784 : }
    1229             : 
    1230             : // ES #sec-get-%typedarray%.prototype.set
    1231         224 : TF_BUILTIN(TypedArrayPrototypeSet, TypedArrayBuiltinsAssembler) {
    1232             :   const char* method_name = "%TypedArray%.prototype.set";
    1233             :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    1234             :   CodeStubArguments args(
    1235             :       this,
    1236         168 :       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount)));
    1237             : 
    1238          56 :   Label if_source_is_typed_array(this), if_source_is_fast_jsarray(this),
    1239          56 :       if_offset_is_out_of_bounds(this, Label::kDeferred),
    1240          56 :       if_source_too_large(this, Label::kDeferred),
    1241          56 :       if_receiver_is_not_typedarray(this, Label::kDeferred);
    1242             : 
    1243             :   // Check the receiver is a typed array.
    1244          56 :   TNode<Object> receiver = args.GetReceiver();
    1245         112 :   GotoIf(TaggedIsSmi(receiver), &if_receiver_is_not_typedarray);
    1246         112 :   GotoIfNot(IsJSTypedArray(CAST(receiver)), &if_receiver_is_not_typedarray);
    1247             : 
    1248             :   // Normalize offset argument (using ToInteger) and handle heap number cases.
    1249         112 :   TNode<Object> offset = args.GetOptionalArgumentValue(1, SmiConstant(0));
    1250             :   TNode<Number> offset_num =
    1251          56 :       ToInteger_Inline(context, offset, kTruncateMinusZero);
    1252             : 
    1253             :   // Since ToInteger always returns a Smi if the given value is within Smi
    1254             :   // range, and the only corner case of -0.0 has already been truncated to 0.0,
    1255             :   // we can simply throw unless the offset is a non-negative Smi.
    1256             :   // TODO(jgruber): It's an observable spec violation to throw here if
    1257             :   // {offset_num} is a positive number outside the Smi range. Per spec, we need
    1258             :   // to check for detached buffers and call the observable ToObject/ToLength
    1259             :   // operations first.
    1260         112 :   GotoIfNot(TaggedIsPositiveSmi(offset_num), &if_offset_is_out_of_bounds);
    1261             :   TNode<Smi> offset_smi = CAST(offset_num);
    1262             : 
    1263             :   // Check the receiver is not detached.
    1264          56 :   ThrowIfArrayBufferViewBufferIsDetached(context, CAST(receiver), method_name);
    1265             : 
    1266             :   // Check the source argument is valid and whether a fast path can be taken.
    1267          56 :   Label call_runtime(this);
    1268          56 :   TNode<Object> source = args.GetOptionalArgumentValue(0);
    1269         112 :   GotoIf(TaggedIsSmi(source), &call_runtime);
    1270         112 :   GotoIf(IsJSTypedArray(CAST(source)), &if_source_is_typed_array);
    1271             :   BranchIfFastJSArray(source, context, &if_source_is_fast_jsarray,
    1272          56 :                       &call_runtime);
    1273             : 
    1274             :   // Fast path for a typed array source argument.
    1275          56 :   BIND(&if_source_is_typed_array);
    1276             :   {
    1277             :     // Check the source argument is not detached.
    1278          56 :     ThrowIfArrayBufferViewBufferIsDetached(context, CAST(source), method_name);
    1279             : 
    1280             :     SetTypedArraySource(context, CAST(source), CAST(receiver),
    1281             :                         SmiUntag(offset_smi), &call_runtime,
    1282          56 :                         &if_source_too_large);
    1283         112 :     args.PopAndReturn(UndefinedConstant());
    1284             :   }
    1285             : 
    1286             :   // Fast path for a fast JSArray source argument.
    1287          56 :   BIND(&if_source_is_fast_jsarray);
    1288             :   {
    1289             :     SetJSArraySource(context, CAST(source), CAST(receiver),
    1290          56 :                      SmiUntag(offset_smi), &call_runtime, &if_source_too_large);
    1291         112 :     args.PopAndReturn(UndefinedConstant());
    1292             :   }
    1293             : 
    1294          56 :   BIND(&call_runtime);
    1295             :   args.PopAndReturn(CallRuntime(Runtime::kTypedArraySet, context, receiver,
    1296          56 :                                 source, offset_smi));
    1297             : 
    1298          56 :   BIND(&if_offset_is_out_of_bounds);
    1299          56 :   ThrowRangeError(context, MessageTemplate::kTypedArraySetOffsetOutOfBounds);
    1300             : 
    1301          56 :   BIND(&if_source_too_large);
    1302          56 :   ThrowRangeError(context, MessageTemplate::kTypedArraySetSourceTooLarge);
    1303             : 
    1304          56 :   BIND(&if_receiver_is_not_typedarray);
    1305         112 :   ThrowTypeError(context, MessageTemplate::kNotTypedArray);
    1306          56 : }
    1307             : 
    1308             : // ES %TypedArray%.prototype.slice
    1309         280 : TF_BUILTIN(TypedArrayPrototypeSlice, TypedArrayBuiltinsAssembler) {
    1310             :   const char* method_name = "%TypedArray%.prototype.slice";
    1311         112 :   Label call_c(this), call_memmove(this), if_count_is_not_zero(this),
    1312          56 :       if_bigint_mixed_types(this, Label::kDeferred);
    1313             : 
    1314             :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    1315             :   CodeStubArguments args(
    1316             :       this,
    1317         168 :       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount)));
    1318             : 
    1319          56 :   TNode<Object> receiver = args.GetReceiver();
    1320             :   TNode<JSTypedArray> source =
    1321          56 :       ValidateTypedArray(context, receiver, method_name);
    1322             : 
    1323          56 :   TNode<Smi> source_length = LoadJSTypedArrayLength(source);
    1324             : 
    1325             :   // Convert start offset argument to integer, and calculate relative offset.
    1326         112 :   TNode<Object> start = args.GetOptionalArgumentValue(0, SmiConstant(0));
    1327             :   TNode<Smi> start_index =
    1328         112 :       SmiTag(ConvertToRelativeIndex(context, start, SmiUntag(source_length)));
    1329             : 
    1330             :   // Convert end offset argument to integer, and calculate relative offset.
    1331             :   // If end offset is not given or undefined is given, set source_length to
    1332             :   // "end_index".
    1333         112 :   TNode<Object> end = args.GetOptionalArgumentValue(1, UndefinedConstant());
    1334             :   TNode<Smi> end_index =
    1335         112 :       Select<Smi>(IsUndefined(end), [=] { return source_length; },
    1336          56 :                   [=] {
    1337             :                     return SmiTag(ConvertToRelativeIndex(
    1338         168 :                         context, end, SmiUntag(source_length)));
    1339         336 :                   });
    1340             : 
    1341             :   // Create a result array by invoking TypedArraySpeciesCreate.
    1342          56 :   TNode<Smi> count = SmiMax(SmiSub(end_index, start_index), SmiConstant(0));
    1343             :   TNode<JSTypedArray> result_array =
    1344          56 :       TypedArraySpeciesCreateByLength(context, source, count, method_name);
    1345             : 
    1346             :   // If count is zero, return early.
    1347         112 :   GotoIf(SmiGreaterThan(count, SmiConstant(0)), &if_count_is_not_zero);
    1348          56 :   args.PopAndReturn(result_array);
    1349             : 
    1350          56 :   BIND(&if_count_is_not_zero);
    1351             :   // Check the source array is detached or not. We don't need to check if the
    1352             :   // result array is detached or not since TypedArraySpeciesCreate checked it.
    1353             :   CSA_ASSERT(this, Word32BinaryNot(IsDetachedBuffer(LoadObjectField(
    1354             :                        result_array, JSTypedArray::kBufferOffset))));
    1355             :   TNode<JSArrayBuffer> receiver_buffer =
    1356          56 :       LoadJSArrayBufferViewBuffer(CAST(receiver));
    1357          56 :   ThrowIfArrayBufferIsDetached(context, receiver_buffer, method_name);
    1358             : 
    1359             :   // result_array could be a different type from source or share the same
    1360             :   // buffer with the source because of custom species constructor.
    1361             :   // If the types of source and result array are the same and they are not
    1362             :   // sharing the same buffer, use memmove.
    1363         112 :   TNode<Word32T> source_el_kind = LoadElementsKind(source);
    1364         112 :   TNode<Word32T> target_el_kind = LoadElementsKind(result_array);
    1365         112 :   GotoIfNot(Word32Equal(source_el_kind, target_el_kind), &call_c);
    1366             : 
    1367             :   TNode<Object> target_buffer =
    1368             :       LoadObjectField(result_array, JSTypedArray::kBufferOffset);
    1369          56 :   Branch(WordEqual(receiver_buffer, target_buffer), &call_c, &call_memmove);
    1370             : 
    1371          56 :   BIND(&call_memmove);
    1372             :   {
    1373          56 :     GotoIfForceSlowPath(&call_c);
    1374             : 
    1375             :     TNode<IntPtrT> target_data_ptr =
    1376          56 :         UncheckedCast<IntPtrT>(LoadDataPtr(result_array));
    1377             :     TNode<IntPtrT> source_data_ptr =
    1378          56 :         UncheckedCast<IntPtrT>(LoadDataPtr(source));
    1379             : 
    1380          56 :     TNode<IntPtrT> source_el_size = GetTypedArrayElementSize(source_el_kind);
    1381             :     TNode<IntPtrT> source_start_bytes =
    1382             :         IntPtrMul(SmiToIntPtr(start_index), source_el_size);
    1383             :     TNode<IntPtrT> source_start =
    1384          56 :         IntPtrAdd(source_data_ptr, source_start_bytes);
    1385             : 
    1386          56 :     TNode<IntPtrT> count_bytes = IntPtrMul(SmiToIntPtr(count), source_el_size);
    1387             : 
    1388             : #ifdef DEBUG
    1389             :     TNode<UintPtrT> target_byte_length =
    1390             :         LoadJSArrayBufferViewByteLength(result_array);
    1391             :     CSA_ASSERT(this, UintPtrLessThanOrEqual(Unsigned(count_bytes),
    1392             :                                             target_byte_length));
    1393             :     TNode<UintPtrT> source_byte_length =
    1394             :         LoadJSArrayBufferViewByteLength(source);
    1395             :     TNode<UintPtrT> source_size_in_bytes =
    1396             :         UintPtrSub(source_byte_length, Unsigned(source_start_bytes));
    1397             :     CSA_ASSERT(this, UintPtrLessThanOrEqual(Unsigned(count_bytes),
    1398             :                                             source_size_in_bytes));
    1399             : #endif  // DEBUG
    1400             : 
    1401          56 :     CallCMemmove(target_data_ptr, source_start, count_bytes);
    1402          56 :     args.PopAndReturn(result_array);
    1403             :   }
    1404             : 
    1405          56 :   BIND(&call_c);
    1406             :   {
    1407             :     GotoIf(Word32NotEqual(IsBigInt64ElementsKind(source_el_kind),
    1408         168 :                           IsBigInt64ElementsKind(target_el_kind)),
    1409         112 :            &if_bigint_mixed_types);
    1410             : 
    1411             :     CallCCopyTypedArrayElementsSlice(
    1412          56 :         source, result_array, SmiToIntPtr(start_index), SmiToIntPtr(end_index));
    1413          56 :     args.PopAndReturn(result_array);
    1414             :   }
    1415             : 
    1416          56 :   BIND(&if_bigint_mixed_types);
    1417         112 :   ThrowTypeError(context, MessageTemplate::kBigIntMixedTypes);
    1418          56 : }
    1419             : 
    1420             : // ES %TypedArray%.prototype.subarray
    1421         280 : TF_BUILTIN(TypedArrayPrototypeSubArray, TypedArrayBuiltinsAssembler) {
    1422             :   const char* method_name = "%TypedArray%.prototype.subarray";
    1423          56 :   Label offset_done(this);
    1424             : 
    1425             :   TVARIABLE(Smi, var_begin);
    1426             :   TVARIABLE(Smi, var_end);
    1427             : 
    1428             :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    1429             :   CodeStubArguments args(
    1430             :       this,
    1431         168 :       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount)));
    1432             : 
    1433             :   // 1. Let O be the this value.
    1434             :   // 3. If O does not have a [[TypedArrayName]] internal slot, throw a TypeError
    1435             :   // exception.
    1436          56 :   TNode<Object> receiver = args.GetReceiver();
    1437          56 :   ThrowIfNotInstanceType(context, receiver, JS_TYPED_ARRAY_TYPE, method_name);
    1438             : 
    1439             :   TNode<JSTypedArray> source = CAST(receiver);
    1440             : 
    1441             :   // 5. Let buffer be O.[[ViewedArrayBuffer]].
    1442          56 :   TNode<JSArrayBuffer> buffer = GetBuffer(context, source);
    1443             :   // 6. Let srcLength be O.[[ArrayLength]].
    1444          56 :   TNode<Smi> source_length = LoadJSTypedArrayLength(source);
    1445             : 
    1446             :   // 7. Let relativeBegin be ? ToInteger(begin).
    1447             :   // 8. If relativeBegin < 0, let beginIndex be max((srcLength + relativeBegin),
    1448             :   // 0); else let beginIndex be min(relativeBegin, srcLength).
    1449         112 :   TNode<Object> begin = args.GetOptionalArgumentValue(0, SmiConstant(0));
    1450         168 :   var_begin =
    1451         112 :       SmiTag(ConvertToRelativeIndex(context, begin, SmiUntag(source_length)));
    1452             : 
    1453         112 :   TNode<Object> end = args.GetOptionalArgumentValue(1, UndefinedConstant());
    1454             :   // 9. If end is undefined, let relativeEnd be srcLength;
    1455             :   var_end = source_length;
    1456         112 :   GotoIf(IsUndefined(end), &offset_done);
    1457             : 
    1458             :   // else, let relativeEnd be ? ToInteger(end).
    1459             :   // 10. If relativeEnd < 0, let endIndex be max((srcLength + relativeEnd), 0);
    1460             :   // else let endIndex be min(relativeEnd, srcLength).
    1461         168 :   var_end =
    1462         112 :       SmiTag(ConvertToRelativeIndex(context, end, SmiUntag(source_length)));
    1463          56 :   Goto(&offset_done);
    1464             : 
    1465          56 :   BIND(&offset_done);
    1466             : 
    1467             :   // 11. Let newLength be max(endIndex - beginIndex, 0).
    1468             :   TNode<Smi> new_length =
    1469         112 :       SmiMax(SmiSub(var_end.value(), var_begin.value()), SmiConstant(0));
    1470             : 
    1471             :   // 12. Let constructorName be the String value of O.[[TypedArrayName]].
    1472             :   // 13. Let elementSize be the Number value of the Element Size value specified
    1473             :   // in Table 52 for constructorName.
    1474         112 :   TNode<Word32T> element_kind = LoadElementsKind(source);
    1475          56 :   TNode<IntPtrT> element_size = GetTypedArrayElementSize(element_kind);
    1476             : 
    1477             :   // 14. Let srcByteOffset be O.[[ByteOffset]].
    1478             :   TNode<Number> source_byte_offset =
    1479          56 :       ChangeUintPtrToTagged(LoadJSArrayBufferViewByteOffset(source));
    1480             : 
    1481             :   // 15. Let beginByteOffset be srcByteOffset + beginIndex × elementSize.
    1482          56 :   TNode<Number> offset = SmiMul(var_begin.value(), SmiFromIntPtr(element_size));
    1483          56 :   TNode<Number> begin_byte_offset = NumberAdd(source_byte_offset, offset);
    1484             : 
    1485             :   // 16. Let argumentsList be « buffer, beginByteOffset, newLength ».
    1486             :   // 17. Return ? TypedArraySpeciesCreate(O, argumentsList).
    1487             :   args.PopAndReturn(TypedArraySpeciesCreate(
    1488         168 :       method_name, context, source, buffer, begin_byte_offset, new_length));
    1489          56 : }
    1490             : 
    1491             : // ES #sec-get-%typedarray%.prototype-@@tostringtag
    1492         224 : TF_BUILTIN(TypedArrayPrototypeToStringTag, TypedArrayBuiltinsAssembler) {
    1493             :   Node* receiver = Parameter(Descriptor::kReceiver);
    1494          56 :   Label if_receiverisheapobject(this), return_undefined(this);
    1495         112 :   Branch(TaggedIsSmi(receiver), &return_undefined, &if_receiverisheapobject);
    1496             : 
    1497             :   // Dispatch on the elements kind, offset by
    1498             :   // FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND.
    1499             :   size_t const kTypedElementsKindCount = LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND -
    1500             :                                          FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND +
    1501             :                                          1;
    1502             : #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) \
    1503             :   Label return_##type##array(this);               \
    1504             :   BIND(&return_##type##array);                    \
    1505             :   Return(StringConstant(#Type "Array"));
    1506        1288 :   TYPED_ARRAYS(TYPED_ARRAY_CASE)
    1507             : #undef TYPED_ARRAY_CASE
    1508             :   Label* elements_kind_labels[kTypedElementsKindCount] = {
    1509             : #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) &return_##type##array,
    1510             :       TYPED_ARRAYS(TYPED_ARRAY_CASE)
    1511             : #undef TYPED_ARRAY_CASE
    1512          56 :   };
    1513             :   int32_t elements_kinds[kTypedElementsKindCount] = {
    1514             : #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) \
    1515             :   TYPE##_ELEMENTS - FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND,
    1516             :       TYPED_ARRAYS(TYPED_ARRAY_CASE)
    1517             : #undef TYPED_ARRAY_CASE
    1518          56 :   };
    1519             : 
    1520             :   // We offset the dispatch by FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND, so
    1521             :   // that this can be turned into a non-sparse table switch for ideal
    1522             :   // performance.
    1523          56 :   BIND(&if_receiverisheapobject);
    1524             :   Node* elements_kind =
    1525          56 :       Int32Sub(LoadElementsKind(receiver),
    1526         280 :                Int32Constant(FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND));
    1527             :   Switch(elements_kind, &return_undefined, elements_kinds, elements_kind_labels,
    1528          56 :          kTypedElementsKindCount);
    1529             : 
    1530          56 :   BIND(&return_undefined);
    1531         168 :   Return(UndefinedConstant());
    1532          56 : }
    1533             : 
    1534         168 : void TypedArrayBuiltinsAssembler::GenerateTypedArrayPrototypeIterationMethod(
    1535             :     TNode<Context> context, TNode<Object> receiver, const char* method_name,
    1536             :     IterationKind kind) {
    1537         168 :   Label throw_bad_receiver(this, Label::kDeferred);
    1538             : 
    1539         336 :   GotoIf(TaggedIsSmi(receiver), &throw_bad_receiver);
    1540         336 :   GotoIfNot(IsJSTypedArray(CAST(receiver)), &throw_bad_receiver);
    1541             : 
    1542             :   // Check if the {receiver}'s JSArrayBuffer was detached.
    1543         168 :   ThrowIfArrayBufferViewBufferIsDetached(context, CAST(receiver), method_name);
    1544             : 
    1545         336 :   Return(CreateArrayIterator(context, receiver, kind));
    1546             : 
    1547         168 :   BIND(&throw_bad_receiver);
    1548         168 :   ThrowTypeError(context, MessageTemplate::kNotTypedArray, method_name);
    1549         168 : }
    1550             : 
    1551             : // ES #sec-%typedarray%.prototype.values
    1552         280 : TF_BUILTIN(TypedArrayPrototypeValues, TypedArrayBuiltinsAssembler) {
    1553          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    1554          56 :   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
    1555             :   GenerateTypedArrayPrototypeIterationMethod(context, receiver,
    1556             :                                              "%TypedArray%.prototype.values()",
    1557          56 :                                              IterationKind::kValues);
    1558          56 : }
    1559             : 
    1560             : // ES #sec-%typedarray%.prototype.entries
    1561         280 : TF_BUILTIN(TypedArrayPrototypeEntries, TypedArrayBuiltinsAssembler) {
    1562          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    1563          56 :   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
    1564             :   GenerateTypedArrayPrototypeIterationMethod(context, receiver,
    1565             :                                              "%TypedArray%.prototype.entries()",
    1566          56 :                                              IterationKind::kEntries);
    1567          56 : }
    1568             : 
    1569             : // ES #sec-%typedarray%.prototype.keys
    1570         280 : TF_BUILTIN(TypedArrayPrototypeKeys, TypedArrayBuiltinsAssembler) {
    1571          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    1572          56 :   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
    1573             :   GenerateTypedArrayPrototypeIterationMethod(
    1574          56 :       context, receiver, "%TypedArray%.prototype.keys()", IterationKind::kKeys);
    1575          56 : }
    1576             : 
    1577             : // ES6 #sec-%typedarray%.of
    1578         280 : TF_BUILTIN(TypedArrayOf, TypedArrayBuiltinsAssembler) {
    1579          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    1580             : 
    1581             :   // 1. Let len be the actual number of arguments passed to this function.
    1582             :   TNode<IntPtrT> length = ChangeInt32ToIntPtr(
    1583          56 :       UncheckedCast<Int32T>(Parameter(Descriptor::kJSActualArgumentsCount)));
    1584             :   // 2. Let items be the List of arguments passed to this function.
    1585             :   CodeStubArguments args(this, length, nullptr, INTPTR_PARAMETERS,
    1586          56 :                          CodeStubArguments::ReceiverMode::kHasReceiver);
    1587             : 
    1588             :   Label if_not_constructor(this, Label::kDeferred),
    1589          56 :       if_detached(this, Label::kDeferred);
    1590             : 
    1591             :   // 3. Let C be the this value.
    1592             :   // 4. If IsConstructor(C) is false, throw a TypeError exception.
    1593          56 :   TNode<Object> receiver = args.GetReceiver();
    1594         112 :   GotoIf(TaggedIsSmi(receiver), &if_not_constructor);
    1595         112 :   GotoIfNot(IsConstructor(CAST(receiver)), &if_not_constructor);
    1596             : 
    1597             :   // 5. Let newObj be ? TypedArrayCreate(C, len).
    1598             :   TNode<JSTypedArray> new_typed_array = TypedArrayCreateByLength(
    1599          56 :       context, receiver, SmiTag(length), "%TypedArray%.of");
    1600             : 
    1601         112 :   TNode<Word32T> elements_kind = LoadElementsKind(new_typed_array);
    1602             : 
    1603             :   // 6. Let k be 0.
    1604             :   // 7. Repeat, while k < len
    1605             :   //  a. Let kValue be items[k].
    1606             :   //  b. Let Pk be ! ToString(k).
    1607             :   //  c. Perform ? Set(newObj, Pk, kValue, true).
    1608             :   //  d. Increase k by 1.
    1609             :   DispatchTypedArrayByElementsKind(
    1610             :       elements_kind,
    1611         616 :       [&](ElementsKind kind, int size, int typed_array_fun_index) {
    1612             :         TNode<FixedTypedArrayBase> elements =
    1613        1848 :             CAST(LoadElements(new_typed_array));
    1614             :         BuildFastLoop(
    1615         616 :             IntPtrConstant(0), length,
    1616         616 :             [&](Node* index) {
    1617         616 :               TNode<Object> item = args.AtIndex(index, INTPTR_PARAMETERS);
    1618         616 :               TNode<IntPtrT> intptr_index = UncheckedCast<IntPtrT>(index);
    1619         616 :               if (kind == BIGINT64_ELEMENTS || kind == BIGUINT64_ELEMENTS) {
    1620             :                 EmitBigTypedArrayElementStore(new_typed_array, elements,
    1621             :                                               intptr_index, item, context,
    1622         112 :                                               &if_detached);
    1623             :               } else {
    1624             :                 Node* value =
    1625         504 :                     PrepareValueForWriteToTypedArray(item, kind, context);
    1626             : 
    1627             :                 // ToNumber may execute JavaScript code, which could detach
    1628             :                 // the array's buffer.
    1629             :                 Node* buffer = LoadObjectField(new_typed_array,
    1630        1008 :                                                JSTypedArray::kBufferOffset);
    1631        1008 :                 GotoIf(IsDetachedBuffer(buffer), &if_detached);
    1632             : 
    1633             :                 // GC may move backing store in ToNumber, thus load backing
    1634             :                 // store everytime in this loop.
    1635             :                 TNode<RawPtrT> backing_store =
    1636         504 :                     LoadFixedTypedArrayBackingStore(elements);
    1637             :                 StoreElement(backing_store, kind, index, value,
    1638        1008 :                              INTPTR_PARAMETERS);
    1639             :               }
    1640         616 :             },
    1641        3080 :             1, ParameterMode::INTPTR_PARAMETERS, IndexAdvanceMode::kPost);
    1642         728 :       });
    1643             : 
    1644             :   // 8. Return newObj.
    1645          56 :   args.PopAndReturn(new_typed_array);
    1646             : 
    1647          56 :   BIND(&if_not_constructor);
    1648          56 :   ThrowTypeError(context, MessageTemplate::kNotConstructor, receiver);
    1649             : 
    1650          56 :   BIND(&if_detached);
    1651             :   ThrowTypeError(context, MessageTemplate::kDetachedOperation,
    1652         112 :                  "%TypedArray%.of");
    1653          56 : }
    1654             : 
    1655             : // ES6 #sec-%typedarray%.from
    1656         280 : TF_BUILTIN(TypedArrayFrom, TypedArrayBuiltinsAssembler) {
    1657          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    1658             : 
    1659          56 :   Label check_iterator(this), from_array_like(this), fast_path(this),
    1660          56 :       slow_path(this), create_typed_array(this), check_typedarray(this),
    1661          56 :       if_not_constructor(this, Label::kDeferred),
    1662          56 :       if_map_fn_not_callable(this, Label::kDeferred),
    1663          56 :       if_iterator_fn_not_callable(this, Label::kDeferred),
    1664          56 :       if_detached(this, Label::kDeferred);
    1665             : 
    1666             :   CodeStubArguments args(
    1667             :       this,
    1668         168 :       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount)));
    1669          56 :   TNode<Object> source = args.GetOptionalArgumentValue(0);
    1670             : 
    1671             :   // 5. If thisArg is present, let T be thisArg; else let T be undefined.
    1672          56 :   TNode<Object> this_arg = args.GetOptionalArgumentValue(2);
    1673             : 
    1674             :   // 1. Let C be the this value.
    1675             :   // 2. If IsConstructor(C) is false, throw a TypeError exception.
    1676          56 :   TNode<Object> receiver = args.GetReceiver();
    1677         112 :   GotoIf(TaggedIsSmi(receiver), &if_not_constructor);
    1678         112 :   GotoIfNot(IsConstructor(CAST(receiver)), &if_not_constructor);
    1679             : 
    1680             :   // 3. If mapfn is present and mapfn is not undefined, then
    1681          56 :   TNode<Object> map_fn = args.GetOptionalArgumentValue(1);
    1682             :   TVARIABLE(BoolT, mapping, Int32FalseConstant());
    1683         112 :   GotoIf(IsUndefined(map_fn), &check_typedarray);
    1684             : 
    1685             :   //  a. If IsCallable(mapfn) is false, throw a TypeError exception.
    1686             :   //  b. Let mapping be true.
    1687             :   // 4. Else, let mapping be false.
    1688         112 :   GotoIf(TaggedIsSmi(map_fn), &if_map_fn_not_callable);
    1689         112 :   GotoIfNot(IsCallable(CAST(map_fn)), &if_map_fn_not_callable);
    1690             :   mapping = Int32TrueConstant();
    1691          56 :   Goto(&check_typedarray);
    1692             : 
    1693             :   TVARIABLE(Object, final_source);
    1694             :   TVARIABLE(Smi, final_length);
    1695             : 
    1696             :   // We split up this builtin differently to the way it is written in the spec.
    1697             :   // We already have great code in the elements accessor for copying from a
    1698             :   // JSArray into a TypedArray, so we use that when possible. We only avoid
    1699             :   // calling into the elements accessor when we have a mapping function, because
    1700             :   // we can't handle that. Here, presence of a mapping function is the slow
    1701             :   // path. We also combine the two different loops in the specification
    1702             :   // (starting at 7.e and 13) because they are essentially identical. We also
    1703             :   // save on code-size this way.
    1704             : 
    1705             :   // Get the iterator function
    1706          56 :   BIND(&check_typedarray);
    1707             :   TNode<Object> iterator_fn =
    1708         112 :       CAST(GetMethod(context, source, isolate()->factory()->iterator_symbol(),
    1709             :                      &from_array_like));
    1710         112 :   GotoIf(TaggedIsSmi(iterator_fn), &if_iterator_fn_not_callable);
    1711             : 
    1712             :   {
    1713             :     // TypedArrays have iterators, so normally we would go through the
    1714             :     // IterableToList case below, which would convert the TypedArray to a
    1715             :     // JSArray (boxing the values if they won't fit in a Smi).
    1716             :     //
    1717             :     // However, if we can guarantee that the source object has the built-in
    1718             :     // iterator and that the %ArrayIteratorPrototype%.next method has not been
    1719             :     // overridden, then we know the behavior of the iterator: returning the
    1720             :     // values in the TypedArray sequentially from index 0 to length-1.
    1721             :     //
    1722             :     // In this case, we can avoid creating the intermediate array and the
    1723             :     // associated HeapNumbers, and use the fast path in TypedArrayCopyElements
    1724             :     // which uses the same ordering as the default iterator.
    1725             :     //
    1726             :     // Drop through to the default check_iterator behavior if any of these
    1727             :     // checks fail.
    1728             : 
    1729             :     // Check that the source is a TypedArray
    1730         112 :     GotoIf(TaggedIsSmi(source), &check_iterator);
    1731         112 :     GotoIfNot(IsJSTypedArray(CAST(source)), &check_iterator);
    1732             :     TNode<JSArrayBuffer> source_buffer =
    1733          56 :         LoadJSArrayBufferViewBuffer(CAST(source));
    1734         112 :     GotoIf(IsDetachedBuffer(source_buffer), &check_iterator);
    1735             : 
    1736             :     // Check that the iterator function is Builtins::kTypedArrayPrototypeValues
    1737         112 :     GotoIfNot(IsJSFunction(CAST(iterator_fn)), &check_iterator);
    1738             :     TNode<SharedFunctionInfo> shared_info = LoadObjectField<SharedFunctionInfo>(
    1739             :         CAST(iterator_fn), JSFunction::kSharedFunctionInfoOffset);
    1740             :     GotoIfNot(
    1741             :         WordEqual(LoadObjectField(shared_info,
    1742             :                                   SharedFunctionInfo::kFunctionDataOffset),
    1743             :                   SmiConstant(Builtins::kTypedArrayPrototypeValues)),
    1744          56 :         &check_iterator);
    1745             :     // Check that the ArrayIterator prototype's "next" method hasn't been
    1746             :     // overridden
    1747             :     TNode<PropertyCell> protector_cell =
    1748          56 :         CAST(LoadRoot(RootIndex::kArrayIteratorProtector));
    1749             :     GotoIfNot(
    1750             :         WordEqual(LoadObjectField(protector_cell, PropertyCell::kValueOffset),
    1751          56 :                   SmiConstant(Isolate::kProtectorValid)),
    1752          56 :         &check_iterator);
    1753             : 
    1754             :     // Source is a TypedArray with unmodified iterator behavior. Use the
    1755             :     // source object directly, taking advantage of the special-case code in
    1756             :     // TypedArrayCopyElements
    1757          56 :     final_length = LoadJSTypedArrayLength(CAST(source));
    1758             :     final_source = source;
    1759          56 :     Goto(&create_typed_array);
    1760             :   }
    1761             : 
    1762          56 :   BIND(&check_iterator);
    1763             :   {
    1764             :     // 6. Let usingIterator be ? GetMethod(source, @@iterator).
    1765         112 :     GotoIfNot(IsCallable(CAST(iterator_fn)), &if_iterator_fn_not_callable);
    1766             : 
    1767             :     // We are using the iterator.
    1768             :     Label if_length_not_smi(this, Label::kDeferred);
    1769             :     // 7. If usingIterator is not undefined, then
    1770             :     //  a. Let values be ? IterableToList(source, usingIterator).
    1771             :     //  b. Let len be the number of elements in values.
    1772          56 :     TNode<JSArray> values = CAST(
    1773             :         CallBuiltin(Builtins::kIterableToList, context, source, iterator_fn));
    1774             : 
    1775             :     // This is not a spec'd limit, so it doesn't particularly matter when we
    1776             :     // throw the range error for typed array length > MaxSmi.
    1777         112 :     TNode<Object> raw_length = LoadJSArrayLength(values);
    1778         112 :     GotoIfNot(TaggedIsSmi(raw_length), &if_length_not_smi);
    1779             : 
    1780             :     final_length = CAST(raw_length);
    1781             :     final_source = values;
    1782          56 :     Goto(&create_typed_array);
    1783             : 
    1784          56 :     BIND(&if_length_not_smi);
    1785             :     ThrowRangeError(context, MessageTemplate::kInvalidTypedArrayLength,
    1786          56 :                     raw_length);
    1787             :   }
    1788             : 
    1789          56 :   BIND(&from_array_like);
    1790             :   {
    1791             :     // TODO(7881): support larger-than-smi typed array lengths
    1792             :     Label if_length_not_smi(this, Label::kDeferred);
    1793             :     final_source = source;
    1794             : 
    1795             :     // 10. Let len be ? ToLength(? Get(arrayLike, "length")).
    1796             :     TNode<Object> raw_length =
    1797         112 :         GetProperty(context, final_source.value(), LengthStringConstant());
    1798          56 :     final_length = ToSmiLength(raw_length, context, &if_length_not_smi);
    1799          56 :     Goto(&create_typed_array);
    1800             : 
    1801          56 :     BIND(&if_length_not_smi);
    1802             :     ThrowRangeError(context, MessageTemplate::kInvalidTypedArrayLength,
    1803          56 :                     raw_length);
    1804             :   }
    1805             : 
    1806             :   TVARIABLE(JSTypedArray, target_obj);
    1807             : 
    1808          56 :   BIND(&create_typed_array);
    1809             :   {
    1810             :     // 7c/11. Let targetObj be ? TypedArrayCreate(C, «len»).
    1811          56 :     target_obj = TypedArrayCreateByLength(
    1812             :         context, receiver, final_length.value(), "%TypedArray%.from");
    1813             : 
    1814          56 :     Branch(mapping.value(), &slow_path, &fast_path);
    1815             :   }
    1816             : 
    1817          56 :   BIND(&fast_path);
    1818             :   {
    1819             :     Label done(this);
    1820         168 :     GotoIf(SmiEqual(final_length.value(), SmiConstant(0)), &done);
    1821             : 
    1822             :     CallRuntime(Runtime::kTypedArrayCopyElements, context, target_obj.value(),
    1823             :                 final_source.value(), final_length.value());
    1824          56 :     Goto(&done);
    1825             : 
    1826          56 :     BIND(&done);
    1827          56 :     args.PopAndReturn(target_obj.value());
    1828             :   }
    1829             : 
    1830          56 :   BIND(&slow_path);
    1831         112 :   TNode<Word32T> elements_kind = LoadElementsKind(target_obj.value());
    1832             : 
    1833             :   // 7e/13 : Copy the elements
    1834          56 :   TNode<FixedTypedArrayBase> elements = CAST(LoadElements(target_obj.value()));
    1835             :   BuildFastLoop(
    1836             :       SmiConstant(0), final_length.value(),
    1837          56 :       [&](Node* index) {
    1838             :         TNode<Object> const k_value =
    1839         224 :             GetProperty(context, final_source.value(), index);
    1840             : 
    1841             :         TNode<Object> const mapped_value =
    1842         280 :             CAST(CallJS(CodeFactory::Call(isolate()), context, map_fn, this_arg,
    1843             :                         k_value, index));
    1844             : 
    1845         112 :         TNode<IntPtrT> intptr_index = SmiUntag(index);
    1846             :         DispatchTypedArrayByElementsKind(
    1847             :             elements_kind,
    1848         616 :             [&](ElementsKind kind, int size, int typed_array_fun_index) {
    1849         616 :               if (kind == BIGINT64_ELEMENTS || kind == BIGUINT64_ELEMENTS) {
    1850             :                 EmitBigTypedArrayElementStore(target_obj.value(), elements,
    1851             :                                               intptr_index, mapped_value,
    1852         224 :                                               context, &if_detached);
    1853             :               } else {
    1854             :                 Node* const final_value = PrepareValueForWriteToTypedArray(
    1855         504 :                     mapped_value, kind, context);
    1856             : 
    1857             :                 // ToNumber may execute JavaScript code, which could detach
    1858             :                 // the array's buffer.
    1859         504 :                 Node* buffer = LoadObjectField(target_obj.value(),
    1860         504 :                                                JSTypedArray::kBufferOffset);
    1861        1008 :                 GotoIf(IsDetachedBuffer(buffer), &if_detached);
    1862             : 
    1863             :                 // GC may move backing store in map_fn, thus load backing
    1864             :                 // store in each iteration of this loop.
    1865             :                 TNode<RawPtrT> backing_store =
    1866         504 :                     LoadFixedTypedArrayBackingStore(elements);
    1867             :                 StoreElement(backing_store, kind, index, final_value,
    1868        1008 :                              SMI_PARAMETERS);
    1869             :               }
    1870         784 :             });
    1871          56 :       },
    1872         168 :       1, ParameterMode::SMI_PARAMETERS, IndexAdvanceMode::kPost);
    1873             : 
    1874          56 :   args.PopAndReturn(target_obj.value());
    1875             : 
    1876          56 :   BIND(&if_not_constructor);
    1877          56 :   ThrowTypeError(context, MessageTemplate::kNotConstructor, receiver);
    1878             : 
    1879          56 :   BIND(&if_map_fn_not_callable);
    1880          56 :   ThrowTypeError(context, MessageTemplate::kCalledNonCallable, map_fn);
    1881             : 
    1882          56 :   BIND(&if_iterator_fn_not_callable);
    1883          56 :   ThrowTypeError(context, MessageTemplate::kIteratorSymbolNonCallable);
    1884             : 
    1885          56 :   BIND(&if_detached);
    1886             :   ThrowTypeError(context, MessageTemplate::kDetachedOperation,
    1887         112 :                  "%TypedArray%.from");
    1888          56 : }
    1889             : 
    1890             : // ES %TypedArray%.prototype.filter
    1891         280 : TF_BUILTIN(TypedArrayPrototypeFilter, TypedArrayBuiltinsAssembler) {
    1892             :   const char* method_name = "%TypedArray%.prototype.filter";
    1893             : 
    1894          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    1895             :   CodeStubArguments args(
    1896             :       this,
    1897         168 :       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount)));
    1898             : 
    1899             :   Label if_callback_not_callable(this, Label::kDeferred),
    1900          56 :       detached(this, Label::kDeferred);
    1901             : 
    1902             :   // 1. Let O be the this value.
    1903             :   // 2. Perform ? ValidateTypedArray(O).
    1904          56 :   TNode<Object> receiver = args.GetReceiver();
    1905             :   TNode<JSTypedArray> source =
    1906          56 :       ValidateTypedArray(context, receiver, method_name);
    1907             : 
    1908             :   // 3. Let len be O.[[ArrayLength]].
    1909          56 :   TNode<Smi> length = LoadJSTypedArrayLength(source);
    1910             : 
    1911             :   // 4. If IsCallable(callbackfn) is false, throw a TypeError exception.
    1912          56 :   TNode<Object> callbackfn = args.GetOptionalArgumentValue(0);
    1913         112 :   GotoIf(TaggedIsSmi(callbackfn), &if_callback_not_callable);
    1914         112 :   GotoIfNot(IsCallable(CAST(callbackfn)), &if_callback_not_callable);
    1915             : 
    1916             :   // 5. If thisArg is present, let T be thisArg; else let T be undefined.
    1917          56 :   TNode<Object> this_arg = args.GetOptionalArgumentValue(1);
    1918             : 
    1919             :   TNode<JSArrayBuffer> source_buffer =
    1920          56 :       LoadObjectField<JSArrayBuffer>(source, JSArrayBufferView::kBufferOffset);
    1921         112 :   TNode<Word32T> elements_kind = LoadElementsKind(source);
    1922         112 :   GrowableFixedArray values(state());
    1923             :   VariableList vars(
    1924         112 :       {values.var_array(), values.var_length(), values.var_capacity()}, zone());
    1925             : 
    1926             :   // 6. Let kept be a new empty List.
    1927             :   // 7. Let k be 0.
    1928             :   // 8. Let captured be 0.
    1929             :   // 9. Repeat, while k < len
    1930             :   BuildFastLoop(
    1931             :       vars, SmiConstant(0), length,
    1932          56 :       [&](Node* index) {
    1933         168 :         GotoIf(IsDetachedBuffer(source_buffer), &detached);
    1934             : 
    1935          56 :         TVARIABLE(Numeric, value);
    1936             :         // a. Let Pk be ! ToString(k).
    1937             :         // b. Let kValue be ? Get(O, Pk).
    1938             :         DispatchTypedArrayByElementsKind(
    1939             :             elements_kind,
    1940         616 :             [&](ElementsKind kind, int size, int typed_array_fun_index) {
    1941             :               TNode<IntPtrT> backing_store =
    1942        1232 :                   UncheckedCast<IntPtrT>(LoadDataPtr(source));
    1943         616 :               value = CAST(LoadFixedTypedArrayElementAsTagged(
    1944             :                   backing_store, index, kind, ParameterMode::SMI_PARAMETERS));
    1945         784 :             });
    1946             : 
    1947             :         // c. Let selected be ToBoolean(Call(callbackfn, T, kValue, k, O))
    1948             :         Node* selected =
    1949             :             CallJS(CodeFactory::Call(isolate()), context, callbackfn, this_arg,
    1950         336 :                    value.value(), index, source);
    1951             : 
    1952         168 :         Label true_continue(this), false_continue(this);
    1953          56 :         BranchIfToBooleanIsTrue(selected, &true_continue, &false_continue);
    1954             : 
    1955          56 :         BIND(&true_continue);
    1956             :         // d. If selected is true, then
    1957             :         //   i. Append kValue to the end of kept.
    1958             :         //   ii. Increase captured by 1.
    1959          56 :         values.Push(value.value());
    1960          56 :         Goto(&false_continue);
    1961             : 
    1962          56 :         BIND(&false_continue);
    1963          56 :       },
    1964         168 :       1, ParameterMode::SMI_PARAMETERS, IndexAdvanceMode::kPost);
    1965             : 
    1966          56 :   TNode<JSArray> values_array = values.ToJSArray(context);
    1967          56 :   TNode<Smi> captured = LoadFastJSArrayLength(values_array);
    1968             : 
    1969             :   // 10. Let A be ? TypedArraySpeciesCreate(O, captured).
    1970             :   TNode<JSTypedArray> result_array =
    1971          56 :       TypedArraySpeciesCreateByLength(context, source, captured, method_name);
    1972             : 
    1973             :   // 11. Let n be 0.
    1974             :   // 12. For each element e of kept, do
    1975             :   //   a. Perform ! Set(A, ! ToString(n), e, true).
    1976             :   //   b. Increment n by 1.
    1977             :   CallRuntime(Runtime::kTypedArrayCopyElements, context, result_array,
    1978             :               values_array, captured);
    1979             : 
    1980             :   // 13. Return A.
    1981          56 :   args.PopAndReturn(result_array);
    1982             : 
    1983          56 :   BIND(&if_callback_not_callable);
    1984          56 :   ThrowTypeError(context, MessageTemplate::kCalledNonCallable, callbackfn);
    1985             : 
    1986          56 :   BIND(&detached);
    1987         112 :   ThrowTypeError(context, MessageTemplate::kDetachedOperation, method_name);
    1988          56 : }
    1989             : 
    1990             : #undef V8_TYPED_ARRAY_MAX_SIZE_IN_HEAP
    1991             : 
    1992             : }  // namespace internal
    1993       94089 : }  // namespace v8

Generated by: LCOV version 1.10