LCOV - code coverage report
Current view: top level - src/builtins - builtins-typed-array-gen.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 612 638 95.9 %
Date: 2019-02-19 Functions: 123 126 97.6 %

          Line data    Source code
       1             : // Copyright 2017 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #include "src/builtins/builtins-typed-array-gen.h"
       6             : 
       7             : #include "src/builtins/builtins-constructor-gen.h"
       8             : #include "src/builtins/builtins-utils-gen.h"
       9             : #include "src/builtins/builtins.h"
      10             : #include "src/builtins/growable-fixed-array-gen.h"
      11             : #include "src/handles-inl.h"
      12             : #include "src/heap/factory-inl.h"
      13             : 
      14             : namespace v8 {
      15             : namespace internal {
      16             : 
      17             : using compiler::Node;
      18             : template <class T>
      19             : using TNode = compiler::TNode<T>;
      20             : 
      21             : // This is needed for gc_mole which will compile this file without the full set
      22             : // of GN defined macros.
      23             : #ifndef V8_TYPED_ARRAY_MAX_SIZE_IN_HEAP
      24             : #define V8_TYPED_ARRAY_MAX_SIZE_IN_HEAP 64
      25             : #endif
      26             : 
      27             : // -----------------------------------------------------------------------------
      28             : // ES6 section 22.2 TypedArray Objects
      29             : 
      30           0 : TNode<Map> TypedArrayBuiltinsAssembler::LoadMapForType(
      31             :     TNode<JSTypedArray> array) {
      32           0 :   TVARIABLE(Map, var_typed_map);
      33           0 :   TNode<Map> array_map = LoadMap(array);
      34           0 :   TNode<Int32T> elements_kind = LoadMapElementsKind(array_map);
      35           0 :   ReadOnlyRoots roots(isolate());
      36             : 
      37             :   DispatchTypedArrayByElementsKind(
      38             :       elements_kind,
      39           0 :       [&](ElementsKind kind, int size, int typed_array_fun_index) {
      40           0 :         Handle<Map> map(roots.MapForFixedTypedArray(kind), isolate());
      41           0 :         var_typed_map = HeapConstant(map);
      42           0 :       });
      43             : 
      44           0 :   return var_typed_map.value();
      45             : }
      46             : 
      47             : // The byte_offset can be higher than Smi range, in which case to perform the
      48             : // pointer arithmetic necessary to calculate external_pointer, converting
      49             : // byte_offset to an intptr is more difficult. The max byte_offset is 8 * MaxSmi
      50             : // on the particular platform. 32 bit platforms are self-limiting, because we
      51             : // can't allocate an array bigger than our 32-bit arithmetic range anyway. 64
      52             : // bit platforms could theoretically have an offset up to 2^35 - 1, so we may
      53             : // need to convert the float heap number to an intptr.
      54         168 : TNode<UintPtrT> TypedArrayBuiltinsAssembler::CalculateExternalPointer(
      55             :     TNode<UintPtrT> backing_store, TNode<Number> byte_offset) {
      56             :   return Unsigned(
      57         168 :       IntPtrAdd(backing_store, ChangeNonnegativeNumberToUintPtr(byte_offset)));
      58             : }
      59             : 
      60             : // Setup the TypedArray which is under construction.
      61             : //  - Set the length.
      62             : //  - Set the byte_offset.
      63             : //  - Set the byte_length.
      64             : //  - Set EmbedderFields to 0.
      65         168 : void TypedArrayBuiltinsAssembler::SetupTypedArray(TNode<JSTypedArray> holder,
      66             :                                                   TNode<Smi> length,
      67             :                                                   TNode<UintPtrT> byte_offset,
      68             :                                                   TNode<UintPtrT> byte_length) {
      69             :   CSA_ASSERT(this, TaggedIsPositiveSmi(length));
      70         168 :   StoreObjectField(holder, JSTypedArray::kLengthOffset, length);
      71             :   StoreObjectFieldNoWriteBarrier(holder, JSArrayBufferView::kByteOffsetOffset,
      72             :                                  byte_offset,
      73         168 :                                  MachineType::PointerRepresentation());
      74             :   StoreObjectFieldNoWriteBarrier(holder, JSArrayBufferView::kByteLengthOffset,
      75             :                                  byte_length,
      76         168 :                                  MachineType::PointerRepresentation());
      77         504 :   for (int offset = JSTypedArray::kHeaderSize;
      78             :        offset < JSTypedArray::kSizeWithEmbedderFields; offset += kTaggedSize) {
      79         336 :     StoreObjectField(holder, offset, SmiConstant(0));
      80             :   }
      81         168 : }
      82             : 
      83             : // Attach an off-heap buffer to a TypedArray.
      84         168 : void TypedArrayBuiltinsAssembler::AttachBuffer(TNode<JSTypedArray> holder,
      85             :                                                TNode<JSArrayBuffer> buffer,
      86             :                                                TNode<Map> map,
      87             :                                                TNode<Smi> length,
      88             :                                                TNode<Number> byte_offset) {
      89             :   CSA_ASSERT(this, TaggedIsPositiveSmi(length));
      90         168 :   StoreObjectField(holder, JSArrayBufferView::kBufferOffset, buffer);
      91             : 
      92         168 :   Node* elements = Allocate(FixedTypedArrayBase::kHeaderSize);
      93         168 :   StoreMapNoWriteBarrier(elements, map);
      94         168 :   StoreObjectFieldNoWriteBarrier(elements, FixedArray::kLengthOffset, length);
      95             :   StoreObjectFieldNoWriteBarrier(
      96         168 :       elements, FixedTypedArrayBase::kBasePointerOffset, SmiConstant(0));
      97             : 
      98             :   TNode<UintPtrT> backing_store =
      99         168 :       LoadObjectField<UintPtrT>(buffer, JSArrayBuffer::kBackingStoreOffset);
     100             : 
     101             :   TNode<UintPtrT> external_pointer =
     102         168 :       CalculateExternalPointer(backing_store, byte_offset);
     103             :   StoreObjectFieldNoWriteBarrier(
     104             :       elements, FixedTypedArrayBase::kExternalPointerOffset, external_pointer,
     105         168 :       MachineType::PointerRepresentation());
     106             : 
     107         168 :   StoreObjectField(holder, JSObject::kElementsOffset, elements);
     108         168 : }
     109             : 
     110             : // Allocate a new ArrayBuffer and initialize it with empty properties and
     111             : // elements.
     112         112 : TNode<JSArrayBuffer> TypedArrayBuiltinsAssembler::AllocateEmptyOnHeapBuffer(
     113             :     TNode<Context> context, TNode<JSTypedArray> holder,
     114             :     TNode<UintPtrT> byte_length) {
     115         112 :   TNode<Context> native_context = LoadNativeContext(context);
     116             :   TNode<Map> map =
     117         112 :       CAST(LoadContextElement(native_context, Context::ARRAY_BUFFER_MAP_INDEX));
     118             :   TNode<FixedArray> empty_fixed_array =
     119         112 :       CAST(LoadRoot(RootIndex::kEmptyFixedArray));
     120             : 
     121             :   TNode<JSArrayBuffer> buffer = UncheckedCast<JSArrayBuffer>(
     122         112 :       Allocate(JSArrayBuffer::kSizeWithEmbedderFields));
     123         112 :   StoreMapNoWriteBarrier(buffer, map);
     124             :   StoreObjectFieldNoWriteBarrier(buffer, JSArray::kPropertiesOrHashOffset,
     125         112 :                                  empty_fixed_array);
     126             :   StoreObjectFieldNoWriteBarrier(buffer, JSArray::kElementsOffset,
     127         112 :                                  empty_fixed_array);
     128             :   // Setup the ArrayBuffer.
     129             :   //  - Set BitField to 0.
     130             :   //  - Set IsExternal and IsDetachable bits of BitFieldSlot.
     131             :   //  - Set the byte_length field to byte_length.
     132             :   //  - Set backing_store to null/Smi(0).
     133             :   //  - Set all embedder fields to Smi(0).
     134             :   if (FIELD_SIZE(JSArrayBuffer::kOptionalPaddingOffset) != 0) {
     135             :     DCHECK_EQ(4, FIELD_SIZE(JSArrayBuffer::kOptionalPaddingOffset));
     136             :     StoreObjectFieldNoWriteBarrier(
     137         112 :         buffer, JSArrayBuffer::kOptionalPaddingOffset, Int32Constant(0),
     138         112 :         MachineRepresentation::kWord32);
     139             :   }
     140             :   int32_t bitfield_value = (1 << JSArrayBuffer::IsExternalBit::kShift) |
     141         112 :                            (1 << JSArrayBuffer::IsDetachableBit::kShift);
     142             :   StoreObjectFieldNoWriteBarrier(buffer, JSArrayBuffer::kBitFieldOffset,
     143         112 :                                  Int32Constant(bitfield_value),
     144         112 :                                  MachineRepresentation::kWord32);
     145             : 
     146             :   StoreObjectFieldNoWriteBarrier(buffer, JSArrayBuffer::kByteLengthOffset,
     147             :                                  byte_length,
     148         112 :                                  MachineType::PointerRepresentation());
     149             :   StoreObjectFieldNoWriteBarrier(buffer, JSArrayBuffer::kBackingStoreOffset,
     150         112 :                                  SmiConstant(0));
     151         336 :   for (int offset = JSArrayBuffer::kHeaderSize;
     152             :        offset < JSArrayBuffer::kSizeWithEmbedderFields; offset += kTaggedSize) {
     153         224 :     StoreObjectFieldNoWriteBarrier(buffer, offset, SmiConstant(0));
     154             :   }
     155             : 
     156         112 :   StoreObjectField(holder, JSArrayBufferView::kBufferOffset, buffer);
     157         112 :   return buffer;
     158             : }
     159             : 
     160         112 : TNode<FixedTypedArrayBase> TypedArrayBuiltinsAssembler::AllocateOnHeapElements(
     161             :     TNode<Map> map, TNode<IntPtrT> total_size, TNode<Number> length) {
     162             :   static const intptr_t fta_base_data_offset =
     163             :       FixedTypedArrayBase::kDataOffset - kHeapObjectTag;
     164             : 
     165             :   CSA_ASSERT(this, IntPtrGreaterThanOrEqual(total_size, IntPtrConstant(0)));
     166             : 
     167             :   // Allocate a FixedTypedArray and set the length, base pointer and external
     168             :   // pointer.
     169             :   CSA_ASSERT(this, IsRegularHeapObjectSize(total_size));
     170             : 
     171         112 :   TNode<Object> elements;
     172             : 
     173         224 :   if (UnalignedLoadSupported(MachineRepresentation::kFloat64) &&
     174         112 :       UnalignedStoreSupported(MachineRepresentation::kFloat64)) {
     175         112 :     elements = AllocateInNewSpace(total_size);
     176             :   } else {
     177           0 :     elements = AllocateInNewSpace(total_size, kDoubleAlignment);
     178             :   }
     179             : 
     180         112 :   StoreMapNoWriteBarrier(elements, map);
     181         112 :   StoreObjectFieldNoWriteBarrier(elements, FixedArray::kLengthOffset, length);
     182             :   StoreObjectFieldNoWriteBarrier(
     183         112 :       elements, FixedTypedArrayBase::kBasePointerOffset, elements);
     184             :   StoreObjectFieldNoWriteBarrier(elements,
     185             :                                  FixedTypedArrayBase::kExternalPointerOffset,
     186         112 :                                  IntPtrConstant(fta_base_data_offset),
     187         224 :                                  MachineType::PointerRepresentation());
     188         112 :   return CAST(elements);
     189             : }
     190             : 
     191        2184 : Node* TypedArrayBuiltinsAssembler::LoadDataPtr(Node* typed_array) {
     192             :   CSA_ASSERT(this, IsJSTypedArray(typed_array));
     193        2184 :   Node* elements = LoadElements(typed_array);
     194             :   CSA_ASSERT(this, IsFixedTypedArray(elements));
     195        2184 :   return LoadFixedTypedArrayBackingStore(CAST(elements));
     196             : }
     197             : 
     198           0 : TNode<BoolT> TypedArrayBuiltinsAssembler::ByteLengthIsValid(
     199             :     TNode<Number> byte_length) {
     200           0 :   Label smi(this), done(this);
     201           0 :   TVARIABLE(BoolT, is_valid);
     202           0 :   GotoIf(TaggedIsSmi(byte_length), &smi);
     203             : 
     204           0 :   TNode<Float64T> float_value = LoadHeapNumberValue(CAST(byte_length));
     205             :   TNode<Float64T> max_byte_length_double =
     206           0 :       Float64Constant(FixedTypedArrayBase::kMaxByteLength);
     207           0 :   is_valid = Float64LessThanOrEqual(float_value, max_byte_length_double);
     208           0 :   Goto(&done);
     209             : 
     210           0 :   BIND(&smi);
     211             :   TNode<IntPtrT> max_byte_length =
     212           0 :       IntPtrConstant(FixedTypedArrayBase::kMaxByteLength);
     213           0 :   is_valid =
     214           0 :       UintPtrLessThanOrEqual(SmiUntag(CAST(byte_length)), max_byte_length);
     215           0 :   Goto(&done);
     216             : 
     217           0 :   BIND(&done);
     218           0 :   return is_valid.value();
     219             : }
     220             : 
     221         280 : TF_BUILTIN(TypedArrayBaseConstructor, TypedArrayBuiltinsAssembler) {
     222          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
     223             :   ThrowTypeError(context, MessageTemplate::kConstructAbstractClass,
     224          56 :                  "TypedArray");
     225          56 : }
     226             : 
     227             : // ES #sec-typedarray-constructors
     228         448 : TF_BUILTIN(TypedArrayConstructor, TypedArrayBuiltinsAssembler) {
     229          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
     230          56 :   TNode<JSFunction> target = CAST(Parameter(Descriptor::kJSTarget));
     231          56 :   TNode<Object> new_target = CAST(Parameter(Descriptor::kJSNewTarget));
     232             :   Node* argc =
     233          56 :       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
     234          56 :   CodeStubArguments args(this, argc);
     235          56 :   Node* arg1 = args.GetOptionalArgumentValue(0);
     236          56 :   Node* arg2 = args.GetOptionalArgumentValue(1);
     237          56 :   Node* arg3 = args.GetOptionalArgumentValue(2);
     238             : 
     239             :   // If NewTarget is undefined, throw a TypeError exception.
     240             :   // All the TypedArray constructors have this as the first step:
     241             :   // https://tc39.github.io/ecma262/#sec-typedarray-constructors
     242          56 :   Label throwtypeerror(this, Label::kDeferred);
     243          56 :   GotoIf(IsUndefined(new_target), &throwtypeerror);
     244             : 
     245             :   Node* result = CallBuiltin(Builtins::kCreateTypedArray, context, target,
     246          56 :                              new_target, arg1, arg2, arg3);
     247          56 :   args.PopAndReturn(result);
     248             : 
     249          56 :   BIND(&throwtypeerror);
     250             :   {
     251             :     TNode<String> name =
     252          56 :         CAST(CallRuntime(Runtime::kGetFunctionName, context, target));
     253          56 :     ThrowTypeError(context, MessageTemplate::kConstructorNotFunction, name);
     254          56 :   }
     255          56 : }
     256             : 
     257             : // ES6 #sec-get-%typedarray%.prototype.bytelength
     258         336 : TF_BUILTIN(TypedArrayPrototypeByteLength, TypedArrayBuiltinsAssembler) {
     259          56 :   const char* const kMethodName = "get TypedArray.prototype.byteLength";
     260          56 :   Node* context = Parameter(Descriptor::kContext);
     261          56 :   Node* receiver = Parameter(Descriptor::kReceiver);
     262             : 
     263             :   // Check if the {receiver} is actually a JSTypedArray.
     264          56 :   ThrowIfNotInstanceType(context, receiver, JS_TYPED_ARRAY_TYPE, kMethodName);
     265             : 
     266             :   // Default to zero if the {receiver}s buffer was detached.
     267             :   TNode<JSArrayBuffer> receiver_buffer =
     268          56 :       LoadJSArrayBufferViewBuffer(CAST(receiver));
     269             :   TNode<UintPtrT> byte_length = Select<UintPtrT>(
     270          56 :       IsDetachedBuffer(receiver_buffer), [=] { return UintPtrConstant(0); },
     271         112 :       [=] { return LoadJSArrayBufferViewByteLength(CAST(receiver)); });
     272          56 :   Return(ChangeUintPtrToTagged(byte_length));
     273          56 : }
     274             : 
     275             : // ES6 #sec-get-%typedarray%.prototype.byteoffset
     276         336 : TF_BUILTIN(TypedArrayPrototypeByteOffset, TypedArrayBuiltinsAssembler) {
     277          56 :   const char* const kMethodName = "get TypedArray.prototype.byteOffset";
     278          56 :   Node* context = Parameter(Descriptor::kContext);
     279          56 :   Node* receiver = Parameter(Descriptor::kReceiver);
     280             : 
     281             :   // Check if the {receiver} is actually a JSTypedArray.
     282          56 :   ThrowIfNotInstanceType(context, receiver, JS_TYPED_ARRAY_TYPE, kMethodName);
     283             : 
     284             :   // Default to zero if the {receiver}s buffer was detached.
     285             :   TNode<JSArrayBuffer> receiver_buffer =
     286          56 :       LoadJSArrayBufferViewBuffer(CAST(receiver));
     287             :   TNode<UintPtrT> byte_offset = Select<UintPtrT>(
     288          56 :       IsDetachedBuffer(receiver_buffer), [=] { return UintPtrConstant(0); },
     289         112 :       [=] { return LoadJSArrayBufferViewByteOffset(CAST(receiver)); });
     290          56 :   Return(ChangeUintPtrToTagged(byte_offset));
     291          56 : }
     292             : 
     293             : // ES6 #sec-get-%typedarray%.prototype.length
     294         336 : TF_BUILTIN(TypedArrayPrototypeLength, TypedArrayBuiltinsAssembler) {
     295          56 :   const char* const kMethodName = "get TypedArray.prototype.length";
     296          56 :   Node* context = Parameter(Descriptor::kContext);
     297          56 :   Node* receiver = Parameter(Descriptor::kReceiver);
     298             : 
     299             :   // Check if the {receiver} is actually a JSTypedArray.
     300          56 :   ThrowIfNotInstanceType(context, receiver, JS_TYPED_ARRAY_TYPE, kMethodName);
     301             : 
     302             :   // Default to zero if the {receiver}s buffer was detached.
     303             :   TNode<JSArrayBuffer> receiver_buffer =
     304          56 :       LoadJSArrayBufferViewBuffer(CAST(receiver));
     305             :   TNode<Smi> length = Select<Smi>(
     306          56 :       IsDetachedBuffer(receiver_buffer), [=] { return SmiConstant(0); },
     307         112 :       [=] { return LoadJSTypedArrayLength(CAST(receiver)); });
     308          56 :   Return(length);
     309          56 : }
     310             : 
     311         112 : TNode<Word32T> TypedArrayBuiltinsAssembler::IsUint8ElementsKind(
     312             :     TNode<Word32T> kind) {
     313         224 :   return Word32Or(Word32Equal(kind, Int32Constant(UINT8_ELEMENTS)),
     314         336 :                   Word32Equal(kind, Int32Constant(UINT8_CLAMPED_ELEMENTS)));
     315             : }
     316             : 
     317         280 : TNode<Word32T> TypedArrayBuiltinsAssembler::IsBigInt64ElementsKind(
     318             :     TNode<Word32T> kind) {
     319         560 :   return Word32Or(Word32Equal(kind, Int32Constant(BIGINT64_ELEMENTS)),
     320         840 :                   Word32Equal(kind, Int32Constant(BIGUINT64_ELEMENTS)));
     321             : }
     322             : 
     323         224 : TNode<IntPtrT> TypedArrayBuiltinsAssembler::GetTypedArrayElementSize(
     324             :     TNode<Word32T> elements_kind) {
     325         224 :   TVARIABLE(IntPtrT, element_size);
     326             : 
     327             :   DispatchTypedArrayByElementsKind(
     328             :       elements_kind,
     329        2464 :       [&](ElementsKind el_kind, int size, int typed_array_fun_index) {
     330        2464 :         element_size = IntPtrConstant(size);
     331        2688 :       });
     332             : 
     333         224 :   return element_size.value();
     334             : }
     335             : 
     336             : TypedArrayBuiltinsFromDSLAssembler::TypedArrayElementsInfo
     337          56 : TypedArrayBuiltinsAssembler::GetTypedArrayElementsInfo(
     338             :     TNode<JSTypedArray> typed_array) {
     339          56 :   TNode<Int32T> elements_kind = LoadElementsKind(typed_array);
     340          56 :   TVARIABLE(Smi, var_element_size);
     341         112 :   TVARIABLE(Map, var_map);
     342          56 :   ReadOnlyRoots roots(isolate());
     343             : 
     344             :   DispatchTypedArrayByElementsKind(
     345             :       elements_kind,
     346         616 :       [&](ElementsKind kind, int size, int typed_array_fun_index) {
     347             :         DCHECK_GT(size, 0);
     348         616 :         var_element_size = SmiConstant(size);
     349             : 
     350         616 :         Handle<Map> map(roots.MapForFixedTypedArray(kind), isolate());
     351         616 :         var_map = HeapConstant(map);
     352         672 :       });
     353             : 
     354             :   return TypedArrayBuiltinsFromDSLAssembler::TypedArrayElementsInfo{
     355         112 :       var_element_size.value(), var_map.value(), elements_kind};
     356             : }
     357             : 
     358         224 : TNode<JSFunction> TypedArrayBuiltinsAssembler::GetDefaultConstructor(
     359             :     TNode<Context> context, TNode<JSTypedArray> exemplar) {
     360         224 :   TVARIABLE(IntPtrT, context_slot);
     361         224 :   TNode<Word32T> elements_kind = LoadElementsKind(exemplar);
     362             : 
     363             :   DispatchTypedArrayByElementsKind(
     364             :       elements_kind,
     365        2464 :       [&](ElementsKind el_kind, int size, int typed_array_function_index) {
     366        2464 :         context_slot = IntPtrConstant(typed_array_function_index);
     367        2688 :       });
     368             : 
     369         448 :   return CAST(
     370         224 :       LoadContextElement(LoadNativeContext(context), context_slot.value()));
     371             : }
     372             : 
     373             : template <class... TArgs>
     374         224 : TNode<JSTypedArray> TypedArrayBuiltinsAssembler::TypedArraySpeciesCreate(
     375             :     const char* method_name, TNode<Context> context,
     376             :     TNode<JSTypedArray> exemplar, TArgs... args) {
     377         224 :   TVARIABLE(JSTypedArray, var_new_typed_array);
     378         448 :   Label slow(this, Label::kDeferred), done(this);
     379             : 
     380             :   // Let defaultConstructor be the intrinsic object listed in column one of
     381             :   // Table 52 for exemplar.[[TypedArrayName]].
     382             :   TNode<JSFunction> default_constructor =
     383         224 :       GetDefaultConstructor(context, exemplar);
     384             : 
     385         224 :   TNode<Map> map = LoadMap(exemplar);
     386         224 :   GotoIfNot(IsPrototypeTypedArrayPrototype(context, map), &slow);
     387         224 :   GotoIf(IsTypedArraySpeciesProtectorCellInvalid(), &slow);
     388             :   {
     389         224 :     const size_t argc = sizeof...(args);
     390             :     static_assert(argc >= 1 && argc <= 3,
     391             :                   "TypedArraySpeciesCreate called with unexpected arguments");
     392         224 :     TNode<Object> arg_list[argc] = {args...};
     393         224 :     TNode<Object> arg0 = argc < 1 ? UndefinedConstant() : arg_list[0];
     394         224 :     TNode<Object> arg1 = argc < 2 ? UndefinedConstant() : arg_list[1];
     395         224 :     TNode<Object> arg2 = argc < 3 ? UndefinedConstant() : arg_list[2];
     396         224 :     var_new_typed_array = UncheckedCast<JSTypedArray>(
     397             :         CallBuiltin(Builtins::kCreateTypedArray, context, default_constructor,
     398             :                     default_constructor, arg0, arg1, arg2));
     399             : #ifdef DEBUG
     400             :     // It is assumed that the CreateTypedArray builtin does not produce a
     401             :     // typed array that fails ValidateTypedArray.
     402             :     TNode<JSArrayBuffer> buffer =
     403             :         LoadJSArrayBufferViewBuffer(var_new_typed_array.value());
     404             :     CSA_ASSERT(this, Word32BinaryNot(IsDetachedBuffer(buffer)));
     405             : #endif  // DEBUG
     406         224 :     Goto(&done);
     407             :   }
     408         224 :   BIND(&slow);
     409             :   {
     410             :     // Let constructor be ? SpeciesConstructor(exemplar, defaultConstructor).
     411             :     TNode<JSReceiver> constructor =
     412         224 :         SpeciesConstructor(context, exemplar, default_constructor);
     413             : 
     414             :     // Let newTypedArray be ? Construct(constructor, argumentList).
     415         224 :     TNode<JSReceiver> new_object = Construct(context, constructor, args...);
     416             : 
     417             :     // Perform ? ValidateTypedArray(newTypedArray).
     418         224 :     var_new_typed_array = ValidateTypedArray(context, new_object, method_name);
     419         224 :     Goto(&done);
     420             :   }
     421             : 
     422         224 :   BIND(&done);
     423         448 :   return var_new_typed_array.value();
     424             : }
     425             : 
     426             : TNode<JSTypedArray>
     427         168 : TypedArrayBuiltinsAssembler::TypedArraySpeciesCreateByLength(
     428             :     TNode<Context> context, TNode<JSTypedArray> exemplar, TNode<Smi> len,
     429             :     const char* method_name) {
     430             :   CSA_ASSERT(this, TaggedIsPositiveSmi(len));
     431             : 
     432             :   TNode<JSTypedArray> new_typed_array =
     433         168 :       TypedArraySpeciesCreate(method_name, context, exemplar, len);
     434             : 
     435         168 :   ThrowIfLengthLessThan(context, new_typed_array, len);
     436         168 :   return new_typed_array;
     437             : }
     438             : 
     439         112 : TNode<JSTypedArray> TypedArrayBuiltinsAssembler::TypedArrayCreateByLength(
     440             :     TNode<Context> context, TNode<Object> constructor, TNode<Smi> len,
     441             :     const char* method_name) {
     442             :   CSA_ASSERT(this, TaggedIsPositiveSmi(len));
     443             : 
     444             :   // Let newTypedArray be ? Construct(constructor, argumentList).
     445         112 :   TNode<Object> new_object = CAST(ConstructJS(CodeFactory::Construct(isolate()),
     446             :                                               context, constructor, len));
     447             : 
     448             :   // Perform ? ValidateTypedArray(newTypedArray).
     449             :   TNode<JSTypedArray> new_typed_array =
     450         112 :       ValidateTypedArray(context, new_object, method_name);
     451             : 
     452         112 :   ThrowIfLengthLessThan(context, new_typed_array, len);
     453         112 :   return new_typed_array;
     454             : }
     455             : 
     456         280 : void TypedArrayBuiltinsAssembler::ThrowIfLengthLessThan(
     457             :     TNode<Context> context, TNode<JSTypedArray> typed_array,
     458             :     TNode<Smi> min_length) {
     459             :   // If typed_array.[[ArrayLength]] < min_length, throw a TypeError exception.
     460         280 :   Label if_length_is_not_short(this);
     461         280 :   TNode<Smi> new_length = LoadJSTypedArrayLength(typed_array);
     462         280 :   GotoIfNot(SmiLessThan(new_length, min_length), &if_length_is_not_short);
     463         280 :   ThrowTypeError(context, MessageTemplate::kTypedArrayTooShort);
     464             : 
     465         280 :   BIND(&if_length_is_not_short);
     466         280 : }
     467             : 
     468          56 : TNode<JSArrayBuffer> TypedArrayBuiltinsAssembler::GetBuffer(
     469             :     TNode<Context> context, TNode<JSTypedArray> array) {
     470         112 :   Label call_runtime(this), done(this);
     471         112 :   TVARIABLE(Object, var_result);
     472             : 
     473          56 :   TNode<Object> buffer = LoadObjectField(array, JSTypedArray::kBufferOffset);
     474          56 :   GotoIf(IsDetachedBuffer(buffer), &call_runtime);
     475             :   TNode<UintPtrT> backing_store = LoadObjectField<UintPtrT>(
     476          56 :       CAST(buffer), JSArrayBuffer::kBackingStoreOffset);
     477          56 :   GotoIf(WordEqual(backing_store, IntPtrConstant(0)), &call_runtime);
     478          56 :   var_result = buffer;
     479          56 :   Goto(&done);
     480             : 
     481          56 :   BIND(&call_runtime);
     482             :   {
     483          56 :     var_result = CallRuntime(Runtime::kTypedArrayGetBuffer, context, array);
     484          56 :     Goto(&done);
     485             :   }
     486             : 
     487          56 :   BIND(&done);
     488         112 :   return CAST(var_result.value());
     489             : }
     490             : 
     491         616 : TNode<JSTypedArray> TypedArrayBuiltinsAssembler::ValidateTypedArray(
     492             :     TNode<Context> context, TNode<Object> obj, const char* method_name) {
     493             :   // If it is not a typed array, throw
     494         616 :   ThrowIfNotInstanceType(context, obj, JS_TYPED_ARRAY_TYPE, method_name);
     495             : 
     496             :   // If the typed array's buffer is detached, throw
     497         616 :   ThrowIfArrayBufferViewBufferIsDetached(context, CAST(obj), method_name);
     498             : 
     499         616 :   return CAST(obj);
     500             : }
     501             : 
     502          56 : void TypedArrayBuiltinsAssembler::SetTypedArraySource(
     503             :     TNode<Context> context, TNode<JSTypedArray> source,
     504             :     TNode<JSTypedArray> target, TNode<IntPtrT> offset, Label* call_runtime,
     505             :     Label* if_source_too_large) {
     506             :   CSA_ASSERT(this, Word32BinaryNot(IsDetachedBuffer(
     507             :                        LoadObjectField(source, JSTypedArray::kBufferOffset))));
     508             :   CSA_ASSERT(this, Word32BinaryNot(IsDetachedBuffer(
     509             :                        LoadObjectField(target, JSTypedArray::kBufferOffset))));
     510             :   CSA_ASSERT(this, IntPtrGreaterThanOrEqual(offset, IntPtrConstant(0)));
     511             :   CSA_ASSERT(this,
     512             :              IntPtrLessThanOrEqual(offset, IntPtrConstant(Smi::kMaxValue)));
     513             : 
     514             :   // Check for possible range errors.
     515             : 
     516          56 :   TNode<IntPtrT> source_length = SmiUntag(LoadJSTypedArrayLength(source));
     517          56 :   TNode<IntPtrT> target_length = SmiUntag(LoadJSTypedArrayLength(target));
     518          56 :   TNode<IntPtrT> required_target_length = IntPtrAdd(source_length, offset);
     519             : 
     520         112 :   GotoIf(IntPtrGreaterThan(required_target_length, target_length),
     521          56 :          if_source_too_large);
     522             : 
     523             :   // Grab pointers and byte lengths we need later on.
     524             : 
     525          56 :   TNode<IntPtrT> target_data_ptr = UncheckedCast<IntPtrT>(LoadDataPtr(target));
     526          56 :   TNode<IntPtrT> source_data_ptr = UncheckedCast<IntPtrT>(LoadDataPtr(source));
     527             : 
     528          56 :   TNode<Word32T> source_el_kind = LoadElementsKind(source);
     529          56 :   TNode<Word32T> target_el_kind = LoadElementsKind(target);
     530             : 
     531          56 :   TNode<IntPtrT> source_el_size = GetTypedArrayElementSize(source_el_kind);
     532          56 :   TNode<IntPtrT> target_el_size = GetTypedArrayElementSize(target_el_kind);
     533             : 
     534             :   // A note on byte lengths: both source- and target byte lengths must be valid,
     535             :   // i.e. it must be possible to allocate an array of the given length. That
     536             :   // means we're safe from overflows in the following multiplication.
     537          56 :   TNode<IntPtrT> source_byte_length = IntPtrMul(source_length, source_el_size);
     538             :   CSA_ASSERT(this,
     539             :              UintPtrGreaterThanOrEqual(source_byte_length, IntPtrConstant(0)));
     540             : 
     541         112 :   Label call_memmove(this), fast_c_call(this), out(this), exception(this);
     542             : 
     543             :   // A fast memmove call can be used when the source and target types are are
     544             :   // the same or either Uint8 or Uint8Clamped.
     545          56 :   GotoIf(Word32Equal(source_el_kind, target_el_kind), &call_memmove);
     546          56 :   GotoIfNot(IsUint8ElementsKind(source_el_kind), &fast_c_call);
     547          56 :   Branch(IsUint8ElementsKind(target_el_kind), &call_memmove, &fast_c_call);
     548             : 
     549          56 :   BIND(&call_memmove);
     550             :   {
     551             :     TNode<IntPtrT> target_start =
     552          56 :         IntPtrAdd(target_data_ptr, IntPtrMul(offset, target_el_size));
     553          56 :     CallCMemmove(target_start, source_data_ptr, source_byte_length);
     554          56 :     Goto(&out);
     555             :   }
     556             : 
     557          56 :   BIND(&fast_c_call);
     558             :   {
     559             :     CSA_ASSERT(
     560             :         this, UintPtrGreaterThanOrEqual(
     561             :                   IntPtrMul(target_length, target_el_size), IntPtrConstant(0)));
     562             : 
     563             :     GotoIf(Word32NotEqual(IsBigInt64ElementsKind(source_el_kind),
     564         112 :                           IsBigInt64ElementsKind(target_el_kind)),
     565          56 :            &exception);
     566             : 
     567          56 :     TNode<IntPtrT> source_length = SmiUntag(LoadJSTypedArrayLength(source));
     568             :     CallCCopyTypedArrayElementsToTypedArray(source, target, source_length,
     569          56 :                                             offset);
     570          56 :     Goto(&out);
     571             :   }
     572             : 
     573          56 :   BIND(&exception);
     574          56 :   ThrowTypeError(context, MessageTemplate::kBigIntMixedTypes);
     575             : 
     576         112 :   BIND(&out);
     577          56 : }
     578             : 
     579          56 : void TypedArrayBuiltinsAssembler::SetJSArraySource(
     580             :     TNode<Context> context, TNode<JSArray> source, TNode<JSTypedArray> target,
     581             :     TNode<IntPtrT> offset, Label* call_runtime, Label* if_source_too_large) {
     582             :   CSA_ASSERT(this, IsFastJSArray(source, context));
     583             :   CSA_ASSERT(this, IntPtrGreaterThanOrEqual(offset, IntPtrConstant(0)));
     584             :   CSA_ASSERT(this,
     585             :              IntPtrLessThanOrEqual(offset, IntPtrConstant(Smi::kMaxValue)));
     586             : 
     587          56 :   TNode<IntPtrT> source_length = SmiUntag(LoadFastJSArrayLength(source));
     588          56 :   TNode<IntPtrT> target_length = SmiUntag(LoadJSTypedArrayLength(target));
     589             : 
     590             :   // Maybe out of bounds?
     591         112 :   GotoIf(IntPtrGreaterThan(IntPtrAdd(source_length, offset), target_length),
     592          56 :          if_source_too_large);
     593             : 
     594             :   // Nothing to do if {source} is empty.
     595         112 :   Label out(this), fast_c_call(this);
     596          56 :   GotoIf(IntPtrEqual(source_length, IntPtrConstant(0)), &out);
     597             : 
     598             :   // Dispatch based on the source elements kind.
     599             :   {
     600             :     // These are the supported elements kinds in TryCopyElementsFastNumber.
     601             :     int32_t values[] = {
     602             :         PACKED_SMI_ELEMENTS, HOLEY_SMI_ELEMENTS, PACKED_DOUBLE_ELEMENTS,
     603             :         HOLEY_DOUBLE_ELEMENTS,
     604          56 :     };
     605             :     Label* labels[] = {
     606             :         &fast_c_call, &fast_c_call, &fast_c_call, &fast_c_call,
     607          56 :     };
     608             :     STATIC_ASSERT(arraysize(values) == arraysize(labels));
     609             : 
     610          56 :     TNode<Int32T> source_elements_kind = LoadElementsKind(source);
     611             :     Switch(source_elements_kind, call_runtime, values, labels,
     612          56 :            arraysize(values));
     613             :   }
     614             : 
     615          56 :   BIND(&fast_c_call);
     616          56 :   GotoIf(IsBigInt64ElementsKind(LoadElementsKind(target)), call_runtime);
     617             :   CallCCopyFastNumberJSArrayElementsToTypedArray(context, source, target,
     618          56 :                                                  source_length, offset);
     619          56 :   Goto(&out);
     620         112 :   BIND(&out);
     621          56 : }
     622             : 
     623         112 : void TypedArrayBuiltinsAssembler::CallCMemmove(TNode<IntPtrT> dest_ptr,
     624             :                                                TNode<IntPtrT> src_ptr,
     625             :                                                TNode<IntPtrT> byte_length) {
     626             :   TNode<ExternalReference> memmove =
     627         112 :       ExternalConstant(ExternalReference::libc_memmove_function());
     628             :   CallCFunction3(MachineType::AnyTagged(), MachineType::Pointer(),
     629             :                  MachineType::Pointer(), MachineType::UintPtr(), memmove,
     630         112 :                  dest_ptr, src_ptr, byte_length);
     631         112 : }
     632             : 
     633          56 : void TypedArrayBuiltinsAssembler::CallCMemcpy(TNode<RawPtrT> dest_ptr,
     634             :                                               TNode<RawPtrT> src_ptr,
     635             :                                               TNode<UintPtrT> byte_length) {
     636             :   TNode<ExternalReference> memcpy =
     637          56 :       ExternalConstant(ExternalReference::libc_memcpy_function());
     638             :   CallCFunction3(MachineType::AnyTagged(), MachineType::Pointer(),
     639             :                  MachineType::Pointer(), MachineType::UintPtr(), memcpy,
     640          56 :                  dest_ptr, src_ptr, byte_length);
     641          56 : }
     642             : 
     643          56 : void TypedArrayBuiltinsAssembler::CallCMemset(TNode<RawPtrT> dest_ptr,
     644             :                                               TNode<IntPtrT> value,
     645             :                                               TNode<UintPtrT> length) {
     646             :   TNode<ExternalReference> memset =
     647          56 :       ExternalConstant(ExternalReference::libc_memset_function());
     648             :   CallCFunction3(MachineType::AnyTagged(), MachineType::Pointer(),
     649             :                  MachineType::IntPtr(), MachineType::UintPtr(), memset,
     650          56 :                  dest_ptr, value, length);
     651          56 : }
     652             : 
     653          56 : void TypedArrayBuiltinsAssembler::
     654             :     CallCCopyFastNumberJSArrayElementsToTypedArray(TNode<Context> context,
     655             :                                                    TNode<JSArray> source,
     656             :                                                    TNode<JSTypedArray> dest,
     657             :                                                    TNode<IntPtrT> source_length,
     658             :                                                    TNode<IntPtrT> offset) {
     659             :   CSA_ASSERT(this,
     660             :              Word32BinaryNot(IsBigInt64ElementsKind(LoadElementsKind(dest))));
     661             :   TNode<ExternalReference> f = ExternalConstant(
     662          56 :       ExternalReference::copy_fast_number_jsarray_elements_to_typed_array());
     663             :   CallCFunction5(MachineType::AnyTagged(), MachineType::AnyTagged(),
     664             :                  MachineType::AnyTagged(), MachineType::AnyTagged(),
     665             :                  MachineType::UintPtr(), MachineType::UintPtr(), f, context,
     666          56 :                  source, dest, source_length, offset);
     667          56 : }
     668             : 
     669          56 : void TypedArrayBuiltinsAssembler::CallCCopyTypedArrayElementsToTypedArray(
     670             :     TNode<JSTypedArray> source, TNode<JSTypedArray> dest,
     671             :     TNode<IntPtrT> source_length, TNode<IntPtrT> offset) {
     672             :   TNode<ExternalReference> f = ExternalConstant(
     673          56 :       ExternalReference::copy_typed_array_elements_to_typed_array());
     674             :   CallCFunction4(MachineType::AnyTagged(), MachineType::AnyTagged(),
     675             :                  MachineType::AnyTagged(), MachineType::UintPtr(),
     676             :                  MachineType::UintPtr(), f, source, dest, source_length,
     677          56 :                  offset);
     678          56 : }
     679             : 
     680          56 : void TypedArrayBuiltinsAssembler::CallCCopyTypedArrayElementsSlice(
     681             :     TNode<JSTypedArray> source, TNode<JSTypedArray> dest, TNode<IntPtrT> start,
     682             :     TNode<IntPtrT> end) {
     683             :   TNode<ExternalReference> f =
     684          56 :       ExternalConstant(ExternalReference::copy_typed_array_elements_slice());
     685             :   CallCFunction4(MachineType::AnyTagged(), MachineType::AnyTagged(),
     686             :                  MachineType::AnyTagged(), MachineType::UintPtr(),
     687          56 :                  MachineType::UintPtr(), f, source, dest, start, end);
     688          56 : }
     689             : 
     690         672 : void TypedArrayBuiltinsAssembler::DispatchTypedArrayByElementsKind(
     691             :     TNode<Word32T> elements_kind, const TypedArraySwitchCase& case_function) {
     692        1344 :   Label next(this), if_unknown_type(this, Label::kDeferred);
     693             : 
     694             :   int32_t elements_kinds[] = {
     695             : #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) TYPE##_ELEMENTS,
     696             :       TYPED_ARRAYS(TYPED_ARRAY_CASE)
     697             : #undef TYPED_ARRAY_CASE
     698         672 :   };
     699             : 
     700             : #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) Label if_##type##array(this);
     701        1344 :   TYPED_ARRAYS(TYPED_ARRAY_CASE)
     702             : #undef TYPED_ARRAY_CASE
     703             : 
     704             :   Label* elements_kind_labels[] = {
     705             : #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) &if_##type##array,
     706             :       TYPED_ARRAYS(TYPED_ARRAY_CASE)
     707             : #undef TYPED_ARRAY_CASE
     708         672 :   };
     709             :   STATIC_ASSERT(arraysize(elements_kinds) == arraysize(elements_kind_labels));
     710             : 
     711             :   Switch(elements_kind, &if_unknown_type, elements_kinds, elements_kind_labels,
     712         672 :          arraysize(elements_kinds));
     713             : 
     714             : #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype)   \
     715             :   BIND(&if_##type##array);                          \
     716             :   {                                                 \
     717             :     case_function(TYPE##_ELEMENTS, sizeof(ctype),   \
     718             :                   Context::TYPE##_ARRAY_FUN_INDEX); \
     719             :     Goto(&next);                                    \
     720             :   }
     721         672 :   TYPED_ARRAYS(TYPED_ARRAY_CASE)
     722             : #undef TYPED_ARRAY_CASE
     723             : 
     724         672 :   BIND(&if_unknown_type);
     725         672 :   Unreachable();
     726             : 
     727        1344 :   BIND(&next);
     728         672 : }
     729             : 
     730          56 : TNode<BoolT> TypedArrayBuiltinsAssembler::IsSharedArrayBuffer(
     731             :     TNode<JSArrayBuffer> buffer) {
     732             :   TNode<Uint32T> bitfield =
     733          56 :       LoadObjectField<Uint32T>(buffer, JSArrayBuffer::kBitFieldOffset);
     734          56 :   return IsSetWord32<JSArrayBuffer::IsSharedBit>(bitfield);
     735             : }
     736             : 
     737             : // ES #sec-get-%typedarray%.prototype.set
     738         336 : TF_BUILTIN(TypedArrayPrototypeSet, TypedArrayBuiltinsAssembler) {
     739          56 :   const char* method_name = "%TypedArray%.prototype.set";
     740          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
     741             :   CodeStubArguments args(
     742             :       this,
     743          56 :       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount)));
     744             : 
     745         112 :   Label if_source_is_typed_array(this), if_source_is_fast_jsarray(this),
     746         112 :       if_offset_is_out_of_bounds(this, Label::kDeferred),
     747         112 :       if_source_too_large(this, Label::kDeferred),
     748         112 :       if_receiver_is_not_typedarray(this, Label::kDeferred);
     749             : 
     750             :   // Check the receiver is a typed array.
     751          56 :   TNode<Object> receiver = args.GetReceiver();
     752          56 :   GotoIf(TaggedIsSmi(receiver), &if_receiver_is_not_typedarray);
     753          56 :   GotoIfNot(IsJSTypedArray(CAST(receiver)), &if_receiver_is_not_typedarray);
     754             : 
     755             :   // Normalize offset argument (using ToInteger) and handle heap number cases.
     756          56 :   TNode<Object> offset = args.GetOptionalArgumentValue(1, SmiConstant(0));
     757             :   TNode<Number> offset_num =
     758          56 :       ToInteger_Inline(context, offset, kTruncateMinusZero);
     759             : 
     760             :   // Since ToInteger always returns a Smi if the given value is within Smi
     761             :   // range, and the only corner case of -0.0 has already been truncated to 0.0,
     762             :   // we can simply throw unless the offset is a non-negative Smi.
     763             :   // TODO(jgruber): It's an observable spec violation to throw here if
     764             :   // {offset_num} is a positive number outside the Smi range. Per spec, we need
     765             :   // to check for detached buffers and call the observable ToObject/ToLength
     766             :   // operations first.
     767          56 :   GotoIfNot(TaggedIsPositiveSmi(offset_num), &if_offset_is_out_of_bounds);
     768          56 :   TNode<Smi> offset_smi = CAST(offset_num);
     769             : 
     770             :   // Check the receiver is not detached.
     771          56 :   ThrowIfArrayBufferViewBufferIsDetached(context, CAST(receiver), method_name);
     772             : 
     773             :   // Check the source argument is valid and whether a fast path can be taken.
     774         112 :   Label call_runtime(this);
     775          56 :   TNode<Object> source = args.GetOptionalArgumentValue(0);
     776          56 :   GotoIf(TaggedIsSmi(source), &call_runtime);
     777          56 :   GotoIf(IsJSTypedArray(CAST(source)), &if_source_is_typed_array);
     778             :   BranchIfFastJSArray(source, context, &if_source_is_fast_jsarray,
     779          56 :                       &call_runtime);
     780             : 
     781             :   // Fast path for a typed array source argument.
     782          56 :   BIND(&if_source_is_typed_array);
     783             :   {
     784             :     // Check the source argument is not detached.
     785          56 :     ThrowIfArrayBufferViewBufferIsDetached(context, CAST(source), method_name);
     786             : 
     787         112 :     SetTypedArraySource(context, CAST(source), CAST(receiver),
     788             :                         SmiUntag(offset_smi), &call_runtime,
     789         168 :                         &if_source_too_large);
     790          56 :     args.PopAndReturn(UndefinedConstant());
     791             :   }
     792             : 
     793             :   // Fast path for a fast JSArray source argument.
     794          56 :   BIND(&if_source_is_fast_jsarray);
     795             :   {
     796         112 :     SetJSArraySource(context, CAST(source), CAST(receiver),
     797         168 :                      SmiUntag(offset_smi), &call_runtime, &if_source_too_large);
     798          56 :     args.PopAndReturn(UndefinedConstant());
     799             :   }
     800             : 
     801          56 :   BIND(&call_runtime);
     802             :   args.PopAndReturn(CallRuntime(Runtime::kTypedArraySet, context, receiver,
     803          56 :                                 source, offset_smi));
     804             : 
     805          56 :   BIND(&if_offset_is_out_of_bounds);
     806          56 :   ThrowRangeError(context, MessageTemplate::kTypedArraySetOffsetOutOfBounds);
     807             : 
     808          56 :   BIND(&if_source_too_large);
     809          56 :   ThrowRangeError(context, MessageTemplate::kTypedArraySetSourceTooLarge);
     810             : 
     811          56 :   BIND(&if_receiver_is_not_typedarray);
     812         112 :   ThrowTypeError(context, MessageTemplate::kNotTypedArray);
     813          56 : }
     814             : 
     815             : // ES %TypedArray%.prototype.slice
     816         336 : TF_BUILTIN(TypedArrayPrototypeSlice, TypedArrayBuiltinsAssembler) {
     817          56 :   const char* method_name = "%TypedArray%.prototype.slice";
     818         112 :   Label call_c(this), call_memmove(this), if_count_is_not_zero(this),
     819         112 :       if_bigint_mixed_types(this, Label::kDeferred);
     820             : 
     821          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
     822             :   CodeStubArguments args(
     823             :       this,
     824          56 :       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount)));
     825             : 
     826          56 :   TNode<Object> receiver = args.GetReceiver();
     827             :   TNode<JSTypedArray> source =
     828          56 :       ValidateTypedArray(context, receiver, method_name);
     829             : 
     830          56 :   TNode<Smi> source_length = LoadJSTypedArrayLength(source);
     831             : 
     832             :   // Convert start offset argument to integer, and calculate relative offset.
     833          56 :   TNode<Object> start = args.GetOptionalArgumentValue(0, SmiConstant(0));
     834             :   TNode<Smi> start_index =
     835          56 :       SmiTag(ConvertToRelativeIndex(context, start, SmiUntag(source_length)));
     836             : 
     837             :   // Convert end offset argument to integer, and calculate relative offset.
     838             :   // If end offset is not given or undefined is given, set source_length to
     839             :   // "end_index".
     840          56 :   TNode<Object> end = args.GetOptionalArgumentValue(1, UndefinedConstant());
     841             :   TNode<Smi> end_index =
     842         168 :       Select<Smi>(IsUndefined(end), [=] { return source_length; },
     843          56 :                   [=] {
     844             :                     return SmiTag(ConvertToRelativeIndex(
     845         112 :                         context, end, SmiUntag(source_length)));
     846         280 :                   });
     847             : 
     848             :   // Create a result array by invoking TypedArraySpeciesCreate.
     849          56 :   TNode<Smi> count = SmiMax(SmiSub(end_index, start_index), SmiConstant(0));
     850             :   TNode<JSTypedArray> result_array =
     851          56 :       TypedArraySpeciesCreateByLength(context, source, count, method_name);
     852             : 
     853             :   // If count is zero, return early.
     854          56 :   GotoIf(SmiGreaterThan(count, SmiConstant(0)), &if_count_is_not_zero);
     855          56 :   args.PopAndReturn(result_array);
     856             : 
     857          56 :   BIND(&if_count_is_not_zero);
     858             :   // Check the source array is detached or not. We don't need to check if the
     859             :   // result array is detached or not since TypedArraySpeciesCreate checked it.
     860             :   CSA_ASSERT(this, Word32BinaryNot(IsDetachedBuffer(LoadObjectField(
     861             :                        result_array, JSTypedArray::kBufferOffset))));
     862             :   TNode<JSArrayBuffer> receiver_buffer =
     863          56 :       LoadJSArrayBufferViewBuffer(CAST(receiver));
     864          56 :   ThrowIfArrayBufferIsDetached(context, receiver_buffer, method_name);
     865             : 
     866             :   // result_array could be a different type from source or share the same
     867             :   // buffer with the source because of custom species constructor.
     868             :   // If the types of source and result array are the same and they are not
     869             :   // sharing the same buffer, use memmove.
     870          56 :   TNode<Word32T> source_el_kind = LoadElementsKind(source);
     871          56 :   TNode<Word32T> target_el_kind = LoadElementsKind(result_array);
     872          56 :   GotoIfNot(Word32Equal(source_el_kind, target_el_kind), &call_c);
     873             : 
     874             :   TNode<Object> target_buffer =
     875          56 :       LoadObjectField(result_array, JSTypedArray::kBufferOffset);
     876          56 :   Branch(WordEqual(receiver_buffer, target_buffer), &call_c, &call_memmove);
     877             : 
     878          56 :   BIND(&call_memmove);
     879             :   {
     880          56 :     GotoIfForceSlowPath(&call_c);
     881             : 
     882             :     TNode<IntPtrT> target_data_ptr =
     883          56 :         UncheckedCast<IntPtrT>(LoadDataPtr(result_array));
     884             :     TNode<IntPtrT> source_data_ptr =
     885          56 :         UncheckedCast<IntPtrT>(LoadDataPtr(source));
     886             : 
     887          56 :     TNode<IntPtrT> source_el_size = GetTypedArrayElementSize(source_el_kind);
     888             :     TNode<IntPtrT> source_start_bytes =
     889          56 :         IntPtrMul(SmiToIntPtr(start_index), source_el_size);
     890             :     TNode<IntPtrT> source_start =
     891          56 :         IntPtrAdd(source_data_ptr, source_start_bytes);
     892             : 
     893          56 :     TNode<IntPtrT> count_bytes = IntPtrMul(SmiToIntPtr(count), source_el_size);
     894             : 
     895             : #ifdef DEBUG
     896             :     TNode<UintPtrT> target_byte_length =
     897             :         LoadJSArrayBufferViewByteLength(result_array);
     898             :     CSA_ASSERT(this, UintPtrLessThanOrEqual(Unsigned(count_bytes),
     899             :                                             target_byte_length));
     900             :     TNode<UintPtrT> source_byte_length =
     901             :         LoadJSArrayBufferViewByteLength(source);
     902             :     TNode<UintPtrT> source_size_in_bytes =
     903             :         UintPtrSub(source_byte_length, Unsigned(source_start_bytes));
     904             :     CSA_ASSERT(this, UintPtrLessThanOrEqual(Unsigned(count_bytes),
     905             :                                             source_size_in_bytes));
     906             : #endif  // DEBUG
     907             : 
     908          56 :     CallCMemmove(target_data_ptr, source_start, count_bytes);
     909          56 :     args.PopAndReturn(result_array);
     910             :   }
     911             : 
     912          56 :   BIND(&call_c);
     913             :   {
     914          56 :     GotoIf(Word32NotEqual(IsBigInt64ElementsKind(source_el_kind),
     915         168 :                           IsBigInt64ElementsKind(target_el_kind)),
     916          56 :            &if_bigint_mixed_types);
     917             : 
     918             :     CallCCopyTypedArrayElementsSlice(
     919          56 :         source, result_array, SmiToIntPtr(start_index), SmiToIntPtr(end_index));
     920          56 :     args.PopAndReturn(result_array);
     921             :   }
     922             : 
     923          56 :   BIND(&if_bigint_mixed_types);
     924         112 :   ThrowTypeError(context, MessageTemplate::kBigIntMixedTypes);
     925          56 : }
     926             : 
     927             : // ES %TypedArray%.prototype.subarray
     928         336 : TF_BUILTIN(TypedArrayPrototypeSubArray, TypedArrayBuiltinsAssembler) {
     929          56 :   const char* method_name = "%TypedArray%.prototype.subarray";
     930          56 :   Label offset_done(this);
     931             : 
     932         112 :   TVARIABLE(Smi, var_begin);
     933         112 :   TVARIABLE(Smi, var_end);
     934             : 
     935          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
     936             :   CodeStubArguments args(
     937             :       this,
     938          56 :       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount)));
     939             : 
     940             :   // 1. Let O be the this value.
     941             :   // 3. If O does not have a [[TypedArrayName]] internal slot, throw a TypeError
     942             :   // exception.
     943          56 :   TNode<Object> receiver = args.GetReceiver();
     944          56 :   ThrowIfNotInstanceType(context, receiver, JS_TYPED_ARRAY_TYPE, method_name);
     945             : 
     946          56 :   TNode<JSTypedArray> source = CAST(receiver);
     947             : 
     948             :   // 5. Let buffer be O.[[ViewedArrayBuffer]].
     949          56 :   TNode<JSArrayBuffer> buffer = GetBuffer(context, source);
     950             :   // 6. Let srcLength be O.[[ArrayLength]].
     951          56 :   TNode<Smi> source_length = LoadJSTypedArrayLength(source);
     952             : 
     953             :   // 7. Let relativeBegin be ? ToInteger(begin).
     954             :   // 8. If relativeBegin < 0, let beginIndex be max((srcLength + relativeBegin),
     955             :   // 0); else let beginIndex be min(relativeBegin, srcLength).
     956          56 :   TNode<Object> begin = args.GetOptionalArgumentValue(0, SmiConstant(0));
     957         112 :   var_begin =
     958         168 :       SmiTag(ConvertToRelativeIndex(context, begin, SmiUntag(source_length)));
     959             : 
     960          56 :   TNode<Object> end = args.GetOptionalArgumentValue(1, UndefinedConstant());
     961             :   // 9. If end is undefined, let relativeEnd be srcLength;
     962          56 :   var_end = source_length;
     963          56 :   GotoIf(IsUndefined(end), &offset_done);
     964             : 
     965             :   // else, let relativeEnd be ? ToInteger(end).
     966             :   // 10. If relativeEnd < 0, let endIndex be max((srcLength + relativeEnd), 0);
     967             :   // else let endIndex be min(relativeEnd, srcLength).
     968         112 :   var_end =
     969         168 :       SmiTag(ConvertToRelativeIndex(context, end, SmiUntag(source_length)));
     970          56 :   Goto(&offset_done);
     971             : 
     972          56 :   BIND(&offset_done);
     973             : 
     974             :   // 11. Let newLength be max(endIndex - beginIndex, 0).
     975             :   TNode<Smi> new_length =
     976          56 :       SmiMax(SmiSub(var_end.value(), var_begin.value()), SmiConstant(0));
     977             : 
     978             :   // 12. Let constructorName be the String value of O.[[TypedArrayName]].
     979             :   // 13. Let elementSize be the Number value of the Element Size value specified
     980             :   // in Table 52 for constructorName.
     981          56 :   TNode<Word32T> element_kind = LoadElementsKind(source);
     982          56 :   TNode<IntPtrT> element_size = GetTypedArrayElementSize(element_kind);
     983             : 
     984             :   // 14. Let srcByteOffset be O.[[ByteOffset]].
     985             :   TNode<Number> source_byte_offset =
     986          56 :       ChangeUintPtrToTagged(LoadJSArrayBufferViewByteOffset(source));
     987             : 
     988             :   // 15. Let beginByteOffset be srcByteOffset + beginIndex × elementSize.
     989          56 :   TNode<Number> offset = SmiMul(var_begin.value(), SmiFromIntPtr(element_size));
     990          56 :   TNode<Number> begin_byte_offset = NumberAdd(source_byte_offset, offset);
     991             : 
     992             :   // 16. Let argumentsList be « buffer, beginByteOffset, newLength ».
     993             :   // 17. Return ? TypedArraySpeciesCreate(O, argumentsList).
     994             :   args.PopAndReturn(TypedArraySpeciesCreate(
     995         112 :       method_name, context, source, buffer, begin_byte_offset, new_length));
     996          56 : }
     997             : 
     998             : // ES #sec-get-%typedarray%.prototype-@@tostringtag
     999         280 : TF_BUILTIN(TypedArrayPrototypeToStringTag, TypedArrayBuiltinsAssembler) {
    1000          56 :   Node* receiver = Parameter(Descriptor::kReceiver);
    1001         112 :   Label if_receiverisheapobject(this), return_undefined(this);
    1002          56 :   Branch(TaggedIsSmi(receiver), &return_undefined, &if_receiverisheapobject);
    1003             : 
    1004             :   // Dispatch on the elements kind, offset by
    1005             :   // FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND.
    1006             :   size_t const kTypedElementsKindCount = LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND -
    1007             :                                          FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND +
    1008          56 :                                          1;
    1009             : #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) \
    1010             :   Label return_##type##array(this);               \
    1011             :   BIND(&return_##type##array);                    \
    1012             :   Return(StringConstant(#Type "Array"));
    1013         112 :   TYPED_ARRAYS(TYPED_ARRAY_CASE)
    1014             : #undef TYPED_ARRAY_CASE
    1015             :   Label* elements_kind_labels[kTypedElementsKindCount] = {
    1016             : #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) &return_##type##array,
    1017             :       TYPED_ARRAYS(TYPED_ARRAY_CASE)
    1018             : #undef TYPED_ARRAY_CASE
    1019          56 :   };
    1020             :   int32_t elements_kinds[kTypedElementsKindCount] = {
    1021             : #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) \
    1022             :   TYPE##_ELEMENTS - FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND,
    1023             :       TYPED_ARRAYS(TYPED_ARRAY_CASE)
    1024             : #undef TYPED_ARRAY_CASE
    1025          56 :   };
    1026             : 
    1027             :   // We offset the dispatch by FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND, so
    1028             :   // that this can be turned into a non-sparse table switch for ideal
    1029             :   // performance.
    1030          56 :   BIND(&if_receiverisheapobject);
    1031             :   Node* elements_kind =
    1032         112 :       Int32Sub(LoadElementsKind(receiver),
    1033         168 :                Int32Constant(FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND));
    1034             :   Switch(elements_kind, &return_undefined, elements_kinds, elements_kind_labels,
    1035          56 :          kTypedElementsKindCount);
    1036             : 
    1037          56 :   BIND(&return_undefined);
    1038         112 :   Return(UndefinedConstant());
    1039          56 : }
    1040             : 
    1041         168 : void TypedArrayBuiltinsAssembler::GenerateTypedArrayPrototypeIterationMethod(
    1042             :     TNode<Context> context, TNode<Object> receiver, const char* method_name,
    1043             :     IterationKind kind) {
    1044         168 :   Label throw_bad_receiver(this, Label::kDeferred);
    1045             : 
    1046         168 :   GotoIf(TaggedIsSmi(receiver), &throw_bad_receiver);
    1047         168 :   GotoIfNot(IsJSTypedArray(CAST(receiver)), &throw_bad_receiver);
    1048             : 
    1049             :   // Check if the {receiver}'s JSArrayBuffer was detached.
    1050         168 :   ThrowIfArrayBufferViewBufferIsDetached(context, CAST(receiver), method_name);
    1051             : 
    1052         168 :   Return(CreateArrayIterator(context, receiver, kind));
    1053             : 
    1054         168 :   BIND(&throw_bad_receiver);
    1055         168 :   ThrowTypeError(context, MessageTemplate::kNotTypedArray, method_name);
    1056         168 : }
    1057             : 
    1058             : // ES #sec-%typedarray%.prototype.values
    1059         336 : TF_BUILTIN(TypedArrayPrototypeValues, TypedArrayBuiltinsAssembler) {
    1060          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    1061          56 :   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
    1062             :   GenerateTypedArrayPrototypeIterationMethod(context, receiver,
    1063             :                                              "%TypedArray%.prototype.values()",
    1064          56 :                                              IterationKind::kValues);
    1065          56 : }
    1066             : 
    1067             : // ES #sec-%typedarray%.prototype.entries
    1068         336 : TF_BUILTIN(TypedArrayPrototypeEntries, TypedArrayBuiltinsAssembler) {
    1069          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    1070          56 :   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
    1071             :   GenerateTypedArrayPrototypeIterationMethod(context, receiver,
    1072             :                                              "%TypedArray%.prototype.entries()",
    1073          56 :                                              IterationKind::kEntries);
    1074          56 : }
    1075             : 
    1076             : // ES #sec-%typedarray%.prototype.keys
    1077         336 : TF_BUILTIN(TypedArrayPrototypeKeys, TypedArrayBuiltinsAssembler) {
    1078          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    1079          56 :   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
    1080             :   GenerateTypedArrayPrototypeIterationMethod(
    1081          56 :       context, receiver, "%TypedArray%.prototype.keys()", IterationKind::kKeys);
    1082          56 : }
    1083             : 
    1084             : // ES6 #sec-%typedarray%.of
    1085         336 : TF_BUILTIN(TypedArrayOf, TypedArrayBuiltinsAssembler) {
    1086          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    1087             : 
    1088             :   // 1. Let len be the actual number of arguments passed to this function.
    1089             :   TNode<IntPtrT> length = ChangeInt32ToIntPtr(
    1090          56 :       UncheckedCast<Int32T>(Parameter(Descriptor::kJSActualArgumentsCount)));
    1091             :   // 2. Let items be the List of arguments passed to this function.
    1092             :   CodeStubArguments args(this, length, nullptr, INTPTR_PARAMETERS,
    1093          56 :                          CodeStubArguments::ReceiverMode::kHasReceiver);
    1094             : 
    1095          56 :   Label if_not_constructor(this, Label::kDeferred),
    1096         112 :       if_detached(this, Label::kDeferred);
    1097             : 
    1098             :   // 3. Let C be the this value.
    1099             :   // 4. If IsConstructor(C) is false, throw a TypeError exception.
    1100          56 :   TNode<Object> receiver = args.GetReceiver();
    1101          56 :   GotoIf(TaggedIsSmi(receiver), &if_not_constructor);
    1102          56 :   GotoIfNot(IsConstructor(CAST(receiver)), &if_not_constructor);
    1103             : 
    1104             :   // 5. Let newObj be ? TypedArrayCreate(C, len).
    1105             :   TNode<JSTypedArray> new_typed_array = TypedArrayCreateByLength(
    1106          56 :       context, receiver, SmiTag(length), "%TypedArray%.of");
    1107             : 
    1108          56 :   TNode<Word32T> elements_kind = LoadElementsKind(new_typed_array);
    1109             : 
    1110             :   // 6. Let k be 0.
    1111             :   // 7. Repeat, while k < len
    1112             :   //  a. Let kValue be items[k].
    1113             :   //  b. Let Pk be ! ToString(k).
    1114             :   //  c. Perform ? Set(newObj, Pk, kValue, true).
    1115             :   //  d. Increase k by 1.
    1116             :   DispatchTypedArrayByElementsKind(
    1117             :       elements_kind,
    1118         616 :       [&](ElementsKind kind, int size, int typed_array_fun_index) {
    1119             :         TNode<FixedTypedArrayBase> elements =
    1120         616 :             CAST(LoadElements(new_typed_array));
    1121             :         BuildFastLoop(
    1122         616 :             IntPtrConstant(0), length,
    1123         616 :             [&](Node* index) {
    1124         616 :               TNode<Object> item = args.AtIndex(index, INTPTR_PARAMETERS);
    1125         616 :               TNode<IntPtrT> intptr_index = UncheckedCast<IntPtrT>(index);
    1126         616 :               if (kind == BIGINT64_ELEMENTS || kind == BIGUINT64_ELEMENTS) {
    1127             :                 EmitBigTypedArrayElementStore(new_typed_array, elements,
    1128             :                                               intptr_index, item, context,
    1129         112 :                                               &if_detached);
    1130             :               } else {
    1131             :                 Node* value =
    1132         504 :                     PrepareValueForWriteToTypedArray(item, kind, context);
    1133             : 
    1134             :                 // ToNumber may execute JavaScript code, which could detach
    1135             :                 // the array's buffer.
    1136             :                 Node* buffer = LoadObjectField(new_typed_array,
    1137         504 :                                                JSTypedArray::kBufferOffset);
    1138         504 :                 GotoIf(IsDetachedBuffer(buffer), &if_detached);
    1139             : 
    1140             :                 // GC may move backing store in ToNumber, thus load backing
    1141             :                 // store everytime in this loop.
    1142             :                 TNode<RawPtrT> backing_store =
    1143         504 :                     LoadFixedTypedArrayBackingStore(elements);
    1144             :                 StoreElement(backing_store, kind, index, value,
    1145         504 :                              INTPTR_PARAMETERS);
    1146             :               }
    1147         616 :             },
    1148        1232 :             1, ParameterMode::INTPTR_PARAMETERS, IndexAdvanceMode::kPost);
    1149         672 :       });
    1150             : 
    1151             :   // 8. Return newObj.
    1152          56 :   args.PopAndReturn(new_typed_array);
    1153             : 
    1154          56 :   BIND(&if_not_constructor);
    1155          56 :   ThrowTypeError(context, MessageTemplate::kNotConstructor, receiver);
    1156             : 
    1157          56 :   BIND(&if_detached);
    1158             :   ThrowTypeError(context, MessageTemplate::kDetachedOperation,
    1159         112 :                  "%TypedArray%.of");
    1160          56 : }
    1161             : 
    1162             : // ES6 #sec-%typedarray%.from
    1163         336 : TF_BUILTIN(TypedArrayFrom, TypedArrayBuiltinsAssembler) {
    1164          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    1165             : 
    1166         112 :   Label check_iterator(this), from_array_like(this), fast_path(this),
    1167         112 :       slow_path(this), create_typed_array(this), check_typedarray(this),
    1168         112 :       if_not_constructor(this, Label::kDeferred),
    1169         112 :       if_map_fn_not_callable(this, Label::kDeferred),
    1170         112 :       if_iterator_fn_not_callable(this, Label::kDeferred),
    1171         112 :       if_detached(this, Label::kDeferred);
    1172             : 
    1173             :   CodeStubArguments args(
    1174             :       this,
    1175          56 :       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount)));
    1176          56 :   TNode<Object> source = args.GetOptionalArgumentValue(0);
    1177             : 
    1178             :   // 5. If thisArg is present, let T be thisArg; else let T be undefined.
    1179          56 :   TNode<Object> this_arg = args.GetOptionalArgumentValue(2);
    1180             : 
    1181             :   // 1. Let C be the this value.
    1182             :   // 2. If IsConstructor(C) is false, throw a TypeError exception.
    1183          56 :   TNode<Object> receiver = args.GetReceiver();
    1184          56 :   GotoIf(TaggedIsSmi(receiver), &if_not_constructor);
    1185          56 :   GotoIfNot(IsConstructor(CAST(receiver)), &if_not_constructor);
    1186             : 
    1187             :   // 3. If mapfn is present and mapfn is not undefined, then
    1188          56 :   TNode<Object> map_fn = args.GetOptionalArgumentValue(1);
    1189         112 :   TVARIABLE(BoolT, mapping, Int32FalseConstant());
    1190          56 :   GotoIf(IsUndefined(map_fn), &check_typedarray);
    1191             : 
    1192             :   //  a. If IsCallable(mapfn) is false, throw a TypeError exception.
    1193             :   //  b. Let mapping be true.
    1194             :   // 4. Else, let mapping be false.
    1195          56 :   GotoIf(TaggedIsSmi(map_fn), &if_map_fn_not_callable);
    1196          56 :   GotoIfNot(IsCallable(CAST(map_fn)), &if_map_fn_not_callable);
    1197          56 :   mapping = Int32TrueConstant();
    1198          56 :   Goto(&check_typedarray);
    1199             : 
    1200         112 :   TVARIABLE(Object, final_source);
    1201         112 :   TVARIABLE(Smi, final_length);
    1202             : 
    1203             :   // We split up this builtin differently to the way it is written in the spec.
    1204             :   // We already have great code in the elements accessor for copying from a
    1205             :   // JSArray into a TypedArray, so we use that when possible. We only avoid
    1206             :   // calling into the elements accessor when we have a mapping function, because
    1207             :   // we can't handle that. Here, presence of a mapping function is the slow
    1208             :   // path. We also combine the two different loops in the specification
    1209             :   // (starting at 7.e and 13) because they are essentially identical. We also
    1210             :   // save on code-size this way.
    1211             : 
    1212             :   // Get the iterator function
    1213          56 :   BIND(&check_typedarray);
    1214             :   TNode<Object> iterator_fn =
    1215         112 :       CAST(GetMethod(context, source, isolate()->factory()->iterator_symbol(),
    1216             :                      &from_array_like));
    1217          56 :   GotoIf(TaggedIsSmi(iterator_fn), &if_iterator_fn_not_callable);
    1218             : 
    1219             :   {
    1220             :     // TypedArrays have iterators, so normally we would go through the
    1221             :     // IterableToList case below, which would convert the TypedArray to a
    1222             :     // JSArray (boxing the values if they won't fit in a Smi).
    1223             :     //
    1224             :     // However, if we can guarantee that the source object has the built-in
    1225             :     // iterator and that the %ArrayIteratorPrototype%.next method has not been
    1226             :     // overridden, then we know the behavior of the iterator: returning the
    1227             :     // values in the TypedArray sequentially from index 0 to length-1.
    1228             :     //
    1229             :     // In this case, we can avoid creating the intermediate array and the
    1230             :     // associated HeapNumbers, and use the fast path in TypedArrayCopyElements
    1231             :     // which uses the same ordering as the default iterator.
    1232             :     //
    1233             :     // Drop through to the default check_iterator behavior if any of these
    1234             :     // checks fail.
    1235             : 
    1236             :     // Check that the source is a TypedArray
    1237          56 :     GotoIf(TaggedIsSmi(source), &check_iterator);
    1238          56 :     GotoIfNot(IsJSTypedArray(CAST(source)), &check_iterator);
    1239             :     TNode<JSArrayBuffer> source_buffer =
    1240          56 :         LoadJSArrayBufferViewBuffer(CAST(source));
    1241          56 :     GotoIf(IsDetachedBuffer(source_buffer), &check_iterator);
    1242             : 
    1243             :     // Check that the iterator function is Builtins::kTypedArrayPrototypeValues
    1244          56 :     GotoIfNot(IsJSFunction(CAST(iterator_fn)), &check_iterator);
    1245             :     TNode<SharedFunctionInfo> shared_info = LoadObjectField<SharedFunctionInfo>(
    1246          56 :         CAST(iterator_fn), JSFunction::kSharedFunctionInfoOffset);
    1247             :     GotoIfNot(
    1248             :         WordEqual(LoadObjectField(shared_info,
    1249             :                                   SharedFunctionInfo::kFunctionDataOffset),
    1250         112 :                   SmiConstant(Builtins::kTypedArrayPrototypeValues)),
    1251          56 :         &check_iterator);
    1252             :     // Check that the ArrayIterator prototype's "next" method hasn't been
    1253             :     // overridden
    1254             :     TNode<PropertyCell> protector_cell =
    1255          56 :         CAST(LoadRoot(RootIndex::kArrayIteratorProtector));
    1256             :     GotoIfNot(
    1257             :         WordEqual(LoadObjectField(protector_cell, PropertyCell::kValueOffset),
    1258         112 :                   SmiConstant(Isolate::kProtectorValid)),
    1259          56 :         &check_iterator);
    1260             : 
    1261             :     // Source is a TypedArray with unmodified iterator behavior. Use the
    1262             :     // source object directly, taking advantage of the special-case code in
    1263             :     // TypedArrayCopyElements
    1264          56 :     final_length = LoadJSTypedArrayLength(CAST(source));
    1265          56 :     final_source = source;
    1266          56 :     Goto(&create_typed_array);
    1267             :   }
    1268             : 
    1269          56 :   BIND(&check_iterator);
    1270             :   {
    1271             :     // 6. Let usingIterator be ? GetMethod(source, @@iterator).
    1272          56 :     GotoIfNot(IsCallable(CAST(iterator_fn)), &if_iterator_fn_not_callable);
    1273             : 
    1274             :     // We are using the iterator.
    1275          56 :     Label if_length_not_smi(this, Label::kDeferred);
    1276             :     // 7. If usingIterator is not undefined, then
    1277             :     //  a. Let values be ? IterableToList(source, usingIterator).
    1278             :     //  b. Let len be the number of elements in values.
    1279          56 :     TNode<JSArray> values = CAST(
    1280             :         CallBuiltin(Builtins::kIterableToList, context, source, iterator_fn));
    1281             : 
    1282             :     // This is not a spec'd limit, so it doesn't particularly matter when we
    1283             :     // throw the range error for typed array length > MaxSmi.
    1284          56 :     TNode<Object> raw_length = LoadJSArrayLength(values);
    1285          56 :     GotoIfNot(TaggedIsSmi(raw_length), &if_length_not_smi);
    1286             : 
    1287          56 :     final_length = CAST(raw_length);
    1288          56 :     final_source = values;
    1289          56 :     Goto(&create_typed_array);
    1290             : 
    1291          56 :     BIND(&if_length_not_smi);
    1292             :     ThrowRangeError(context, MessageTemplate::kInvalidTypedArrayLength,
    1293          56 :                     raw_length);
    1294             :   }
    1295             : 
    1296          56 :   BIND(&from_array_like);
    1297             :   {
    1298             :     // TODO(7881): support larger-than-smi typed array lengths
    1299          56 :     Label if_length_not_smi(this, Label::kDeferred);
    1300          56 :     final_source = source;
    1301             : 
    1302             :     // 10. Let len be ? ToLength(? Get(arrayLike, "length")).
    1303             :     TNode<Object> raw_length =
    1304          56 :         GetProperty(context, final_source.value(), LengthStringConstant());
    1305          56 :     final_length = ToSmiLength(context, raw_length, &if_length_not_smi);
    1306          56 :     Goto(&create_typed_array);
    1307             : 
    1308          56 :     BIND(&if_length_not_smi);
    1309             :     ThrowRangeError(context, MessageTemplate::kInvalidTypedArrayLength,
    1310          56 :                     raw_length);
    1311             :   }
    1312             : 
    1313         112 :   TVARIABLE(JSTypedArray, target_obj);
    1314             : 
    1315          56 :   BIND(&create_typed_array);
    1316             :   {
    1317             :     // 7c/11. Let targetObj be ? TypedArrayCreate(C, «len»).
    1318          56 :     target_obj = TypedArrayCreateByLength(
    1319          56 :         context, receiver, final_length.value(), "%TypedArray%.from");
    1320             : 
    1321          56 :     Branch(mapping.value(), &slow_path, &fast_path);
    1322             :   }
    1323             : 
    1324          56 :   BIND(&fast_path);
    1325             :   {
    1326          56 :     Label done(this);
    1327          56 :     GotoIf(SmiEqual(final_length.value(), SmiConstant(0)), &done);
    1328             : 
    1329             :     CallRuntime(Runtime::kTypedArrayCopyElements, context, target_obj.value(),
    1330          56 :                 final_source.value(), final_length.value());
    1331          56 :     Goto(&done);
    1332             : 
    1333          56 :     BIND(&done);
    1334          56 :     args.PopAndReturn(target_obj.value());
    1335             :   }
    1336             : 
    1337          56 :   BIND(&slow_path);
    1338          56 :   TNode<Word32T> elements_kind = LoadElementsKind(target_obj.value());
    1339             : 
    1340             :   // 7e/13 : Copy the elements
    1341          56 :   TNode<FixedTypedArrayBase> elements = CAST(LoadElements(target_obj.value()));
    1342             :   BuildFastLoop(
    1343          56 :       SmiConstant(0), final_length.value(),
    1344          56 :       [&](Node* index) {
    1345             :         TNode<Object> const k_value =
    1346          56 :             GetProperty(context, final_source.value(), index);
    1347             : 
    1348             :         TNode<Object> const mapped_value =
    1349          56 :             CAST(CallJS(CodeFactory::Call(isolate()), context, map_fn, this_arg,
    1350             :                         k_value, index));
    1351             : 
    1352          56 :         TNode<IntPtrT> intptr_index = SmiUntag(index);
    1353             :         DispatchTypedArrayByElementsKind(
    1354             :             elements_kind,
    1355         616 :             [&](ElementsKind kind, int size, int typed_array_fun_index) {
    1356         616 :               if (kind == BIGINT64_ELEMENTS || kind == BIGUINT64_ELEMENTS) {
    1357             :                 EmitBigTypedArrayElementStore(target_obj.value(), elements,
    1358             :                                               intptr_index, mapped_value,
    1359         112 :                                               context, &if_detached);
    1360             :               } else {
    1361             :                 Node* const final_value = PrepareValueForWriteToTypedArray(
    1362         504 :                     mapped_value, kind, context);
    1363             : 
    1364             :                 // ToNumber may execute JavaScript code, which could detach
    1365             :                 // the array's buffer.
    1366         504 :                 Node* buffer = LoadObjectField(target_obj.value(),
    1367         504 :                                                JSTypedArray::kBufferOffset);
    1368         504 :                 GotoIf(IsDetachedBuffer(buffer), &if_detached);
    1369             : 
    1370             :                 // GC may move backing store in map_fn, thus load backing
    1371             :                 // store in each iteration of this loop.
    1372             :                 TNode<RawPtrT> backing_store =
    1373         504 :                     LoadFixedTypedArrayBackingStore(elements);
    1374             :                 StoreElement(backing_store, kind, index, final_value,
    1375         504 :                              SMI_PARAMETERS);
    1376             :               }
    1377         672 :             });
    1378          56 :       },
    1379         112 :       1, ParameterMode::SMI_PARAMETERS, IndexAdvanceMode::kPost);
    1380             : 
    1381          56 :   args.PopAndReturn(target_obj.value());
    1382             : 
    1383          56 :   BIND(&if_not_constructor);
    1384          56 :   ThrowTypeError(context, MessageTemplate::kNotConstructor, receiver);
    1385             : 
    1386          56 :   BIND(&if_map_fn_not_callable);
    1387          56 :   ThrowTypeError(context, MessageTemplate::kCalledNonCallable, map_fn);
    1388             : 
    1389          56 :   BIND(&if_iterator_fn_not_callable);
    1390          56 :   ThrowTypeError(context, MessageTemplate::kIteratorSymbolNonCallable);
    1391             : 
    1392          56 :   BIND(&if_detached);
    1393             :   ThrowTypeError(context, MessageTemplate::kDetachedOperation,
    1394         112 :                  "%TypedArray%.from");
    1395          56 : }
    1396             : 
    1397             : // ES %TypedArray%.prototype.filter
    1398         336 : TF_BUILTIN(TypedArrayPrototypeFilter, TypedArrayBuiltinsAssembler) {
    1399          56 :   const char* method_name = "%TypedArray%.prototype.filter";
    1400             : 
    1401          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    1402             :   CodeStubArguments args(
    1403             :       this,
    1404          56 :       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount)));
    1405             : 
    1406          56 :   Label if_callback_not_callable(this, Label::kDeferred),
    1407         112 :       detached(this, Label::kDeferred);
    1408             : 
    1409             :   // 1. Let O be the this value.
    1410             :   // 2. Perform ? ValidateTypedArray(O).
    1411          56 :   TNode<Object> receiver = args.GetReceiver();
    1412             :   TNode<JSTypedArray> source =
    1413          56 :       ValidateTypedArray(context, receiver, method_name);
    1414             : 
    1415             :   // 3. Let len be O.[[ArrayLength]].
    1416          56 :   TNode<Smi> length = LoadJSTypedArrayLength(source);
    1417             : 
    1418             :   // 4. If IsCallable(callbackfn) is false, throw a TypeError exception.
    1419          56 :   TNode<Object> callbackfn = args.GetOptionalArgumentValue(0);
    1420          56 :   GotoIf(TaggedIsSmi(callbackfn), &if_callback_not_callable);
    1421          56 :   GotoIfNot(IsCallable(CAST(callbackfn)), &if_callback_not_callable);
    1422             : 
    1423             :   // 5. If thisArg is present, let T be thisArg; else let T be undefined.
    1424          56 :   TNode<Object> this_arg = args.GetOptionalArgumentValue(1);
    1425             : 
    1426             :   TNode<JSArrayBuffer> source_buffer =
    1427          56 :       LoadObjectField<JSArrayBuffer>(source, JSArrayBufferView::kBufferOffset);
    1428          56 :   TNode<Word32T> elements_kind = LoadElementsKind(source);
    1429         112 :   GrowableFixedArray values(state());
    1430             :   VariableList vars(
    1431         112 :       {values.var_array(), values.var_length(), values.var_capacity()}, zone());
    1432             : 
    1433             :   // 6. Let kept be a new empty List.
    1434             :   // 7. Let k be 0.
    1435             :   // 8. Let captured be 0.
    1436             :   // 9. Repeat, while k < len
    1437             :   BuildFastLoop(
    1438          56 :       vars, SmiConstant(0), length,
    1439          56 :       [&](Node* index) {
    1440          56 :         GotoIf(IsDetachedBuffer(source_buffer), &detached);
    1441             : 
    1442          56 :         TVARIABLE(Numeric, value);
    1443             :         // a. Let Pk be ! ToString(k).
    1444             :         // b. Let kValue be ? Get(O, Pk).
    1445             :         DispatchTypedArrayByElementsKind(
    1446             :             elements_kind,
    1447         616 :             [&](ElementsKind kind, int size, int typed_array_fun_index) {
    1448             :               TNode<IntPtrT> backing_store =
    1449         616 :                   UncheckedCast<IntPtrT>(LoadDataPtr(source));
    1450        1232 :               value = CAST(LoadFixedTypedArrayElementAsTagged(
    1451         616 :                   backing_store, index, kind, ParameterMode::SMI_PARAMETERS));
    1452         672 :             });
    1453             : 
    1454             :         // c. Let selected be ToBoolean(Call(callbackfn, T, kValue, k, O))
    1455             :         Node* selected =
    1456             :             CallJS(CodeFactory::Call(isolate()), context, callbackfn, this_arg,
    1457          56 :                    value.value(), index, source);
    1458             : 
    1459         112 :         Label true_continue(this), false_continue(this);
    1460          56 :         BranchIfToBooleanIsTrue(selected, &true_continue, &false_continue);
    1461             : 
    1462          56 :         BIND(&true_continue);
    1463             :         // d. If selected is true, then
    1464             :         //   i. Append kValue to the end of kept.
    1465             :         //   ii. Increase captured by 1.
    1466          56 :         values.Push(value.value());
    1467          56 :         Goto(&false_continue);
    1468             : 
    1469          56 :         BIND(&false_continue);
    1470          56 :       },
    1471         112 :       1, ParameterMode::SMI_PARAMETERS, IndexAdvanceMode::kPost);
    1472             : 
    1473          56 :   TNode<JSArray> values_array = values.ToJSArray(context);
    1474          56 :   TNode<Smi> captured = LoadFastJSArrayLength(values_array);
    1475             : 
    1476             :   // 10. Let A be ? TypedArraySpeciesCreate(O, captured).
    1477             :   TNode<JSTypedArray> result_array =
    1478          56 :       TypedArraySpeciesCreateByLength(context, source, captured, method_name);
    1479             : 
    1480             :   // 11. Let n be 0.
    1481             :   // 12. For each element e of kept, do
    1482             :   //   a. Perform ! Set(A, ! ToString(n), e, true).
    1483             :   //   b. Increment n by 1.
    1484             :   CallRuntime(Runtime::kTypedArrayCopyElements, context, result_array,
    1485          56 :               values_array, captured);
    1486             : 
    1487             :   // 13. Return A.
    1488          56 :   args.PopAndReturn(result_array);
    1489             : 
    1490          56 :   BIND(&if_callback_not_callable);
    1491          56 :   ThrowTypeError(context, MessageTemplate::kCalledNonCallable, callbackfn);
    1492             : 
    1493          56 :   BIND(&detached);
    1494         112 :   ThrowTypeError(context, MessageTemplate::kDetachedOperation, method_name);
    1495          56 : }
    1496             : 
    1497             : #undef V8_TYPED_ARRAY_MAX_SIZE_IN_HEAP
    1498             : 
    1499             : }  // namespace internal
    1500       86739 : }  // namespace v8

Generated by: LCOV version 1.10