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