LCOV - code coverage report
Current view: top level - src/builtins - builtins-typed-array-gen.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 431 443 97.3 %
Date: 2019-04-17 Functions: 54 56 96.4 %

          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             : #include "torque-generated/builtins-typed-array-createtypedarray-from-dsl-gen.h"
      14             : 
      15             : namespace v8 {
      16             : namespace internal {
      17             : 
      18             : using compiler::Node;
      19             : template <class T>
      20             : using TNode = compiler::TNode<T>;
      21             : 
      22             : // This is needed for gc_mole which will compile this file without the full set
      23             : // of GN defined macros.
      24             : #ifndef V8_TYPED_ARRAY_MAX_SIZE_IN_HEAP
      25             : #define V8_TYPED_ARRAY_MAX_SIZE_IN_HEAP 64
      26             : #endif
      27             : 
      28             : // -----------------------------------------------------------------------------
      29             : // ES6 section 22.2 TypedArray Objects
      30             : 
      31           0 : TNode<Map> TypedArrayBuiltinsAssembler::LoadMapForType(
      32             :     TNode<JSTypedArray> array) {
      33           0 :   TVARIABLE(Map, var_typed_map);
      34           0 :   TNode<Map> array_map = LoadMap(array);
      35           0 :   TNode<Int32T> elements_kind = LoadMapElementsKind(array_map);
      36           0 :   ReadOnlyRoots roots(isolate());
      37             : 
      38           0 :   DispatchTypedArrayByElementsKind(
      39             :       elements_kind,
      40           0 :       [&](ElementsKind kind, int size, int typed_array_fun_index) {
      41           0 :         Handle<Map> map(roots.MapForFixedTypedArray(kind), isolate());
      42           0 :         var_typed_map = HeapConstant(map);
      43           0 :       });
      44             : 
      45           0 :   return var_typed_map.value();
      46             : }
      47             : 
      48             : // Setup the TypedArray which is under construction.
      49             : //  - Set the length.
      50             : //  - Set the byte_offset.
      51             : //  - Set the byte_length.
      52             : //  - Set EmbedderFields to 0.
      53         168 : void TypedArrayBuiltinsAssembler::SetupTypedArray(TNode<JSTypedArray> holder,
      54             :                                                   TNode<Smi> length,
      55             :                                                   TNode<UintPtrT> byte_offset,
      56             :                                                   TNode<UintPtrT> byte_length) {
      57             :   CSA_ASSERT(this, TaggedIsPositiveSmi(length));
      58         168 :   StoreObjectField(holder, JSTypedArray::kLengthOffset, length);
      59             :   StoreObjectFieldNoWriteBarrier(holder, JSArrayBufferView::kByteOffsetOffset,
      60             :                                  byte_offset,
      61         168 :                                  MachineType::PointerRepresentation());
      62             :   StoreObjectFieldNoWriteBarrier(holder, JSArrayBufferView::kByteLengthOffset,
      63             :                                  byte_length,
      64         168 :                                  MachineType::PointerRepresentation());
      65         336 :   for (int offset = JSTypedArray::kHeaderSize;
      66         504 :        offset < JSTypedArray::kSizeWithEmbedderFields; offset += kTaggedSize) {
      67         672 :     StoreObjectField(holder, offset, SmiConstant(0));
      68             :   }
      69         168 : }
      70             : 
      71             : // Allocate a new ArrayBuffer and initialize it with empty properties and
      72             : // elements.
      73         112 : TNode<JSArrayBuffer> TypedArrayBuiltinsAssembler::AllocateEmptyOnHeapBuffer(
      74             :     TNode<Context> context, TNode<JSTypedArray> holder,
      75             :     TNode<UintPtrT> byte_length) {
      76         112 :   TNode<Context> native_context = LoadNativeContext(context);
      77             :   TNode<Map> map =
      78         112 :       CAST(LoadContextElement(native_context, Context::ARRAY_BUFFER_MAP_INDEX));
      79             :   TNode<FixedArray> empty_fixed_array =
      80         112 :       CAST(LoadRoot(RootIndex::kEmptyFixedArray));
      81             : 
      82             :   TNode<JSArrayBuffer> buffer = UncheckedCast<JSArrayBuffer>(
      83         112 :       Allocate(JSArrayBuffer::kSizeWithEmbedderFields));
      84         112 :   StoreMapNoWriteBarrier(buffer, map);
      85             :   StoreObjectFieldNoWriteBarrier(buffer, JSArray::kPropertiesOrHashOffset,
      86             :                                  empty_fixed_array);
      87             :   StoreObjectFieldNoWriteBarrier(buffer, JSArray::kElementsOffset,
      88             :                                  empty_fixed_array);
      89             :   // Setup the ArrayBuffer.
      90             :   //  - Set BitField to 0.
      91             :   //  - Set IsExternal and IsDetachable bits of BitFieldSlot.
      92             :   //  - Set the byte_length field to byte_length.
      93             :   //  - Set backing_store to null/Smi(0).
      94             :   //  - Set all embedder fields to Smi(0).
      95             :   if (FIELD_SIZE(JSArrayBuffer::kOptionalPaddingOffset) != 0) {
      96             :     DCHECK_EQ(4, FIELD_SIZE(JSArrayBuffer::kOptionalPaddingOffset));
      97             :     StoreObjectFieldNoWriteBarrier(
      98         224 :         buffer, JSArrayBuffer::kOptionalPaddingOffset, Int32Constant(0),
      99         112 :         MachineRepresentation::kWord32);
     100             :   }
     101             :   int32_t bitfield_value = (1 << JSArrayBuffer::IsExternalBit::kShift) |
     102             :                            (1 << JSArrayBuffer::IsDetachableBit::kShift);
     103             :   StoreObjectFieldNoWriteBarrier(buffer, JSArrayBuffer::kBitFieldOffset,
     104         224 :                                  Int32Constant(bitfield_value),
     105         112 :                                  MachineRepresentation::kWord32);
     106             : 
     107             :   StoreObjectFieldNoWriteBarrier(buffer, JSArrayBuffer::kByteLengthOffset,
     108             :                                  byte_length,
     109         112 :                                  MachineType::PointerRepresentation());
     110             :   StoreObjectFieldNoWriteBarrier(buffer, JSArrayBuffer::kBackingStoreOffset,
     111         224 :                                  IntPtrConstant(0),
     112         112 :                                  MachineType::PointerRepresentation());
     113         224 :   for (int offset = JSArrayBuffer::kHeaderSize;
     114         336 :        offset < JSArrayBuffer::kSizeWithEmbedderFields; offset += kTaggedSize) {
     115         224 :     StoreObjectFieldNoWriteBarrier(buffer, offset, SmiConstant(0));
     116             :   }
     117             : 
     118         112 :   StoreObjectField(holder, JSArrayBufferView::kBufferOffset, buffer);
     119         112 :   return buffer;
     120             : }
     121             : 
     122         112 : TNode<FixedTypedArrayBase> TypedArrayBuiltinsAssembler::AllocateOnHeapElements(
     123             :     TNode<Map> map, TNode<IntPtrT> total_size, TNode<Number> length) {
     124             :   CSA_ASSERT(this, IntPtrGreaterThanOrEqual(total_size, IntPtrConstant(0)));
     125             : 
     126             :   // Allocate a FixedTypedArray and set the length, base pointer and external
     127             :   // pointer.
     128             :   CSA_ASSERT(this, IsRegularHeapObjectSize(total_size));
     129             : 
     130             :   TNode<Object> elements;
     131             : 
     132         224 :   if (UnalignedLoadSupported(MachineRepresentation::kFloat64) &&
     133         112 :       UnalignedStoreSupported(MachineRepresentation::kFloat64)) {
     134         224 :     elements = AllocateInNewSpace(total_size);
     135             :   } else {
     136           0 :     elements = AllocateInNewSpace(total_size, kDoubleAlignment);
     137             :   }
     138             : 
     139         112 :   StoreMapNoWriteBarrier(elements, map);
     140         112 :   StoreObjectFieldNoWriteBarrier(elements, FixedArray::kLengthOffset, length);
     141             :   StoreObjectFieldNoWriteBarrier(
     142         112 :       elements, FixedTypedArrayBase::kBasePointerOffset, elements);
     143             :   StoreObjectFieldNoWriteBarrier(
     144             :       elements, FixedTypedArrayBase::kExternalPointerOffset,
     145         224 :       IntPtrConstant(FixedTypedArrayBase::ExternalPointerValueForOnHeapArray()),
     146         112 :       MachineType::PointerRepresentation());
     147         112 :   return CAST(elements);
     148             : }
     149             : 
     150        1568 : TNode<RawPtrT> TypedArrayBuiltinsAssembler::LoadDataPtr(
     151             :     TNode<JSTypedArray> typed_array) {
     152             :   TNode<FixedArrayBase> elements = LoadElements(typed_array);
     153             :   CSA_ASSERT(this, IsFixedTypedArray(elements));
     154        1568 :   return LoadFixedTypedArrayBackingStore(CAST(elements));
     155             : }
     156             : 
     157         224 : TF_BUILTIN(TypedArrayBaseConstructor, TypedArrayBuiltinsAssembler) {
     158             :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
     159          56 :   ThrowTypeError(context, MessageTemplate::kConstructAbstractClass,
     160          56 :                  "TypedArray");
     161          56 : }
     162             : 
     163             : // ES #sec-typedarray-constructors
     164         224 : TF_BUILTIN(TypedArrayConstructor, TypedArrayBuiltinsAssembler) {
     165             :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
     166             :   TNode<JSFunction> target = CAST(Parameter(Descriptor::kJSTarget));
     167             :   TNode<Object> new_target = CAST(Parameter(Descriptor::kJSNewTarget));
     168             :   Node* argc =
     169         112 :       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
     170          56 :   CodeStubArguments args(this, argc);
     171         112 :   Node* arg1 = args.GetOptionalArgumentValue(0);
     172         112 :   Node* arg2 = args.GetOptionalArgumentValue(1);
     173         112 :   Node* arg3 = args.GetOptionalArgumentValue(2);
     174             : 
     175             :   // If NewTarget is undefined, throw a TypeError exception.
     176             :   // All the TypedArray constructors have this as the first step:
     177             :   // https://tc39.github.io/ecma262/#sec-typedarray-constructors
     178          56 :   Label throwtypeerror(this, Label::kDeferred);
     179         112 :   GotoIf(IsUndefined(new_target), &throwtypeerror);
     180             : 
     181         112 :   Node* result = CallBuiltin(Builtins::kCreateTypedArray, context, target,
     182          56 :                              new_target, arg1, arg2, arg3);
     183          56 :   args.PopAndReturn(result);
     184             : 
     185          56 :   BIND(&throwtypeerror);
     186             :   {
     187             :     TNode<String> name =
     188             :         CAST(CallRuntime(Runtime::kGetFunctionName, context, target));
     189          56 :     ThrowTypeError(context, MessageTemplate::kConstructorNotFunction, name);
     190             :   }
     191          56 : }
     192             : 
     193             : // ES6 #sec-get-%typedarray%.prototype.bytelength
     194         224 : TF_BUILTIN(TypedArrayPrototypeByteLength, TypedArrayBuiltinsAssembler) {
     195             :   const char* const kMethodName = "get TypedArray.prototype.byteLength";
     196             :   Node* context = Parameter(Descriptor::kContext);
     197             :   Node* receiver = Parameter(Descriptor::kReceiver);
     198             : 
     199             :   // Check if the {receiver} is actually a JSTypedArray.
     200          56 :   ThrowIfNotInstanceType(context, receiver, JS_TYPED_ARRAY_TYPE, kMethodName);
     201             : 
     202             :   // Default to zero if the {receiver}s buffer was detached.
     203             :   TNode<JSArrayBuffer> receiver_buffer =
     204          56 :       LoadJSArrayBufferViewBuffer(CAST(receiver));
     205             :   TNode<UintPtrT> byte_length = Select<UintPtrT>(
     206          56 :       IsDetachedBuffer(receiver_buffer), [=] { return UintPtrConstant(0); },
     207         224 :       [=] { return LoadJSArrayBufferViewByteLength(CAST(receiver)); });
     208         112 :   Return(ChangeUintPtrToTagged(byte_length));
     209          56 : }
     210             : 
     211             : // ES6 #sec-get-%typedarray%.prototype.byteoffset
     212         224 : TF_BUILTIN(TypedArrayPrototypeByteOffset, TypedArrayBuiltinsAssembler) {
     213             :   const char* const kMethodName = "get TypedArray.prototype.byteOffset";
     214             :   Node* context = Parameter(Descriptor::kContext);
     215             :   Node* receiver = Parameter(Descriptor::kReceiver);
     216             : 
     217             :   // Check if the {receiver} is actually a JSTypedArray.
     218          56 :   ThrowIfNotInstanceType(context, receiver, JS_TYPED_ARRAY_TYPE, kMethodName);
     219             : 
     220             :   // Default to zero if the {receiver}s buffer was detached.
     221             :   TNode<JSArrayBuffer> receiver_buffer =
     222          56 :       LoadJSArrayBufferViewBuffer(CAST(receiver));
     223             :   TNode<UintPtrT> byte_offset = Select<UintPtrT>(
     224          56 :       IsDetachedBuffer(receiver_buffer), [=] { return UintPtrConstant(0); },
     225         224 :       [=] { return LoadJSArrayBufferViewByteOffset(CAST(receiver)); });
     226         112 :   Return(ChangeUintPtrToTagged(byte_offset));
     227          56 : }
     228             : 
     229             : // ES6 #sec-get-%typedarray%.prototype.length
     230         224 : TF_BUILTIN(TypedArrayPrototypeLength, TypedArrayBuiltinsAssembler) {
     231             :   const char* const kMethodName = "get TypedArray.prototype.length";
     232             :   Node* context = Parameter(Descriptor::kContext);
     233             :   Node* receiver = Parameter(Descriptor::kReceiver);
     234             : 
     235             :   // Check if the {receiver} is actually a JSTypedArray.
     236          56 :   ThrowIfNotInstanceType(context, receiver, JS_TYPED_ARRAY_TYPE, kMethodName);
     237             : 
     238             :   // Default to zero if the {receiver}s buffer was detached.
     239             :   TNode<JSArrayBuffer> receiver_buffer =
     240          56 :       LoadJSArrayBufferViewBuffer(CAST(receiver));
     241             :   TNode<Smi> length = Select<Smi>(
     242          56 :       IsDetachedBuffer(receiver_buffer), [=] { return SmiConstant(0); },
     243         224 :       [=] { return LoadJSTypedArrayLength(CAST(receiver)); });
     244          56 :   Return(length);
     245          56 : }
     246             : 
     247         112 : TNode<Word32T> TypedArrayBuiltinsAssembler::IsUint8ElementsKind(
     248             :     TNode<Word32T> kind) {
     249         336 :   return Word32Or(Word32Equal(kind, Int32Constant(UINT8_ELEMENTS)),
     250         448 :                   Word32Equal(kind, Int32Constant(UINT8_CLAMPED_ELEMENTS)));
     251             : }
     252             : 
     253         280 : TNode<Word32T> TypedArrayBuiltinsAssembler::IsBigInt64ElementsKind(
     254             :     TNode<Word32T> kind) {
     255         840 :   return Word32Or(Word32Equal(kind, Int32Constant(BIGINT64_ELEMENTS)),
     256        1120 :                   Word32Equal(kind, Int32Constant(BIGUINT64_ELEMENTS)));
     257             : }
     258             : 
     259         112 : TNode<IntPtrT> TypedArrayBuiltinsAssembler::GetTypedArrayElementSize(
     260             :     TNode<Word32T> elements_kind) {
     261         112 :   TVARIABLE(IntPtrT, element_size);
     262             : 
     263         112 :   DispatchTypedArrayByElementsKind(
     264             :       elements_kind,
     265             :       [&](ElementsKind el_kind, int size, int typed_array_fun_index) {
     266        1232 :         element_size = IntPtrConstant(size);
     267         112 :       });
     268             : 
     269         112 :   return element_size.value();
     270             : }
     271             : 
     272             : TypedArrayBuiltinsFromDSLAssembler::TypedArrayElementsInfo
     273         168 : TypedArrayBuiltinsAssembler::GetTypedArrayElementsInfo(
     274             :     TNode<JSTypedArray> typed_array) {
     275         168 :   TNode<Int32T> elements_kind = LoadElementsKind(typed_array);
     276         168 :   TVARIABLE(UintPtrT, var_size_log2);
     277             :   TVARIABLE(Map, var_map);
     278         168 :   ReadOnlyRoots roots(isolate());
     279             : 
     280         336 :   DispatchTypedArrayByElementsKind(
     281             :       elements_kind,
     282        1848 :       [&](ElementsKind kind, int size, int typed_array_fun_index) {
     283             :         DCHECK_GT(size, 0);
     284        7392 :         var_size_log2 = UintPtrConstant(ElementsKindToShiftSize(kind));
     285             : 
     286        1848 :         Handle<Map> map(roots.MapForFixedTypedArray(kind), isolate());
     287        3696 :         var_map = HeapConstant(map);
     288        2016 :       });
     289             : 
     290             :   return TypedArrayBuiltinsFromDSLAssembler::TypedArrayElementsInfo{
     291         336 :       var_size_log2.value(), var_map.value(), elements_kind};
     292             : }
     293             : 
     294         224 : TNode<JSFunction> TypedArrayBuiltinsAssembler::GetDefaultConstructor(
     295             :     TNode<Context> context, TNode<JSTypedArray> exemplar) {
     296         224 :   TVARIABLE(IntPtrT, context_slot);
     297         448 :   TNode<Word32T> elements_kind = LoadElementsKind(exemplar);
     298             : 
     299         224 :   DispatchTypedArrayByElementsKind(
     300             :       elements_kind,
     301             :       [&](ElementsKind el_kind, int size, int typed_array_function_index) {
     302        2464 :         context_slot = IntPtrConstant(typed_array_function_index);
     303         224 :       });
     304             : 
     305         672 :   return CAST(
     306             :       LoadContextElement(LoadNativeContext(context), context_slot.value()));
     307             : }
     308             : 
     309         112 : TNode<JSTypedArray> TypedArrayBuiltinsAssembler::TypedArrayCreateByLength(
     310             :     TNode<Context> context, TNode<Object> constructor, TNode<Smi> len,
     311             :     const char* method_name) {
     312             :   CSA_ASSERT(this, TaggedIsPositiveSmi(len));
     313             : 
     314             :   // Let newTypedArray be ? Construct(constructor, argumentList).
     315         336 :   TNode<Object> new_object = CAST(ConstructJS(CodeFactory::Construct(isolate()),
     316             :                                               context, constructor, len));
     317             : 
     318             :   // Perform ? ValidateTypedArray(newTypedArray).
     319             :   TNode<JSTypedArray> new_typed_array =
     320         112 :       ValidateTypedArray(context, new_object, method_name);
     321             : 
     322         112 :   ThrowIfLengthLessThan(context, new_typed_array, len);
     323         112 :   return new_typed_array;
     324             : }
     325             : 
     326         112 : void TypedArrayBuiltinsAssembler::ThrowIfLengthLessThan(
     327             :     TNode<Context> context, TNode<JSTypedArray> typed_array,
     328             :     TNode<Smi> min_length) {
     329             :   // If typed_array.[[ArrayLength]] < min_length, throw a TypeError exception.
     330         224 :   Label if_length_is_not_short(this);
     331         112 :   TNode<Smi> new_length = LoadJSTypedArrayLength(typed_array);
     332         224 :   GotoIfNot(SmiLessThan(new_length, min_length), &if_length_is_not_short);
     333         112 :   ThrowTypeError(context, MessageTemplate::kTypedArrayTooShort);
     334             : 
     335         112 :   BIND(&if_length_is_not_short);
     336         112 : }
     337             : 
     338          56 : TNode<JSArrayBuffer> TypedArrayBuiltinsAssembler::GetBuffer(
     339             :     TNode<Context> context, TNode<JSTypedArray> array) {
     340         112 :   Label call_runtime(this), done(this);
     341             :   TVARIABLE(Object, var_result);
     342             : 
     343          56 :   TNode<Object> buffer = LoadObjectField(array, JSTypedArray::kBufferOffset);
     344         112 :   GotoIf(IsDetachedBuffer(buffer), &call_runtime);
     345             :   TNode<UintPtrT> backing_store = LoadObjectField<UintPtrT>(
     346             :       CAST(buffer), JSArrayBuffer::kBackingStoreOffset);
     347         168 :   GotoIf(WordEqual(backing_store, IntPtrConstant(0)), &call_runtime);
     348             :   var_result = buffer;
     349          56 :   Goto(&done);
     350             : 
     351          56 :   BIND(&call_runtime);
     352             :   {
     353             :     var_result = CallRuntime(Runtime::kTypedArrayGetBuffer, context, array);
     354          56 :     Goto(&done);
     355             :   }
     356             : 
     357          56 :   BIND(&done);
     358          56 :   return CAST(var_result.value());
     359             : }
     360             : 
     361         560 : TNode<JSTypedArray> TypedArrayBuiltinsAssembler::ValidateTypedArray(
     362             :     TNode<Context> context, TNode<Object> obj, const char* method_name) {
     363             :   // If it is not a typed array, throw
     364         560 :   ThrowIfNotInstanceType(context, obj, JS_TYPED_ARRAY_TYPE, method_name);
     365             : 
     366             :   // If the typed array's buffer is detached, throw
     367         560 :   ThrowIfArrayBufferViewBufferIsDetached(context, CAST(obj), method_name);
     368             : 
     369         560 :   return CAST(obj);
     370             : }
     371             : 
     372          56 : void TypedArrayBuiltinsAssembler::SetTypedArraySource(
     373             :     TNode<Context> context, TNode<JSTypedArray> source,
     374             :     TNode<JSTypedArray> target, TNode<IntPtrT> offset, Label* call_runtime,
     375             :     Label* if_source_too_large) {
     376             :   CSA_ASSERT(this, Word32BinaryNot(IsDetachedBuffer(
     377             :                        LoadObjectField(source, JSTypedArray::kBufferOffset))));
     378             :   CSA_ASSERT(this, Word32BinaryNot(IsDetachedBuffer(
     379             :                        LoadObjectField(target, JSTypedArray::kBufferOffset))));
     380             :   CSA_ASSERT(this, IntPtrGreaterThanOrEqual(offset, IntPtrConstant(0)));
     381             :   CSA_ASSERT(this,
     382             :              IntPtrLessThanOrEqual(offset, IntPtrConstant(Smi::kMaxValue)));
     383             : 
     384             :   // Check for possible range errors.
     385             : 
     386         112 :   TNode<IntPtrT> source_length = SmiUntag(LoadJSTypedArrayLength(source));
     387         112 :   TNode<IntPtrT> target_length = SmiUntag(LoadJSTypedArrayLength(target));
     388          56 :   TNode<IntPtrT> required_target_length = IntPtrAdd(source_length, offset);
     389             : 
     390         112 :   GotoIf(IntPtrGreaterThan(required_target_length, target_length),
     391          56 :          if_source_too_large);
     392             : 
     393             :   // Grab pointers and byte lengths we need later on.
     394             : 
     395          56 :   TNode<RawPtrT> target_data_ptr = LoadDataPtr(target);
     396          56 :   TNode<RawPtrT> source_data_ptr = LoadDataPtr(source);
     397             : 
     398         112 :   TNode<Word32T> source_el_kind = LoadElementsKind(source);
     399         112 :   TNode<Word32T> target_el_kind = LoadElementsKind(target);
     400             : 
     401          56 :   TNode<IntPtrT> source_el_size = GetTypedArrayElementSize(source_el_kind);
     402          56 :   TNode<IntPtrT> target_el_size = GetTypedArrayElementSize(target_el_kind);
     403             : 
     404             :   // A note on byte lengths: both source- and target byte lengths must be valid,
     405             :   // i.e. it must be possible to allocate an array of the given length. That
     406             :   // means we're safe from overflows in the following multiplication.
     407             :   TNode<IntPtrT> source_byte_length = IntPtrMul(source_length, source_el_size);
     408             :   CSA_ASSERT(this,
     409             :              UintPtrGreaterThanOrEqual(source_byte_length, IntPtrConstant(0)));
     410             : 
     411          56 :   Label call_memmove(this), fast_c_call(this), out(this), exception(this);
     412             : 
     413             :   // A fast memmove call can be used when the source and target types are are
     414             :   // the same or either Uint8 or Uint8Clamped.
     415         112 :   GotoIf(Word32Equal(source_el_kind, target_el_kind), &call_memmove);
     416         112 :   GotoIfNot(IsUint8ElementsKind(source_el_kind), &fast_c_call);
     417         112 :   Branch(IsUint8ElementsKind(target_el_kind), &call_memmove, &fast_c_call);
     418             : 
     419          56 :   BIND(&call_memmove);
     420             :   {
     421             :     TNode<RawPtrT> target_start =
     422          56 :         RawPtrAdd(target_data_ptr, IntPtrMul(offset, target_el_size));
     423          56 :     CallCMemmove(target_start, source_data_ptr, Unsigned(source_byte_length));
     424          56 :     Goto(&out);
     425             :   }
     426             : 
     427          56 :   BIND(&fast_c_call);
     428             :   {
     429             :     CSA_ASSERT(
     430             :         this, UintPtrGreaterThanOrEqual(
     431             :                   IntPtrMul(target_length, target_el_size), IntPtrConstant(0)));
     432             : 
     433         224 :     GotoIf(Word32NotEqual(IsBigInt64ElementsKind(source_el_kind),
     434         168 :                           IsBigInt64ElementsKind(target_el_kind)),
     435          56 :            &exception);
     436             : 
     437         112 :     TNode<IntPtrT> source_length = SmiUntag(LoadJSTypedArrayLength(source));
     438             :     CallCCopyTypedArrayElementsToTypedArray(source, target, source_length,
     439          56 :                                             offset);
     440          56 :     Goto(&out);
     441             :   }
     442             : 
     443          56 :   BIND(&exception);
     444          56 :   ThrowTypeError(context, MessageTemplate::kBigIntMixedTypes);
     445             : 
     446          56 :   BIND(&out);
     447          56 : }
     448             : 
     449          56 : void TypedArrayBuiltinsAssembler::SetJSArraySource(
     450             :     TNode<Context> context, TNode<JSArray> source, TNode<JSTypedArray> target,
     451             :     TNode<IntPtrT> offset, Label* call_runtime, Label* if_source_too_large) {
     452             :   CSA_ASSERT(this, IsFastJSArray(source, context));
     453             :   CSA_ASSERT(this, IntPtrGreaterThanOrEqual(offset, IntPtrConstant(0)));
     454             :   CSA_ASSERT(this,
     455             :              IntPtrLessThanOrEqual(offset, IntPtrConstant(Smi::kMaxValue)));
     456             : 
     457         112 :   TNode<IntPtrT> source_length = SmiUntag(LoadFastJSArrayLength(source));
     458         112 :   TNode<IntPtrT> target_length = SmiUntag(LoadJSTypedArrayLength(target));
     459             : 
     460             :   // Maybe out of bounds?
     461         168 :   GotoIf(IntPtrGreaterThan(IntPtrAdd(source_length, offset), target_length),
     462          56 :          if_source_too_large);
     463             : 
     464             :   // Nothing to do if {source} is empty.
     465          56 :   Label out(this), fast_c_call(this);
     466         168 :   GotoIf(IntPtrEqual(source_length, IntPtrConstant(0)), &out);
     467             : 
     468             :   // Dispatch based on the source elements kind.
     469             :   {
     470             :     // These are the supported elements kinds in TryCopyElementsFastNumber.
     471             :     int32_t values[] = {
     472             :         PACKED_SMI_ELEMENTS, HOLEY_SMI_ELEMENTS, PACKED_DOUBLE_ELEMENTS,
     473             :         HOLEY_DOUBLE_ELEMENTS,
     474          56 :     };
     475             :     Label* labels[] = {
     476             :         &fast_c_call, &fast_c_call, &fast_c_call, &fast_c_call,
     477          56 :     };
     478             :     STATIC_ASSERT(arraysize(values) == arraysize(labels));
     479             : 
     480          56 :     TNode<Int32T> source_elements_kind = LoadElementsKind(source);
     481             :     Switch(source_elements_kind, call_runtime, values, labels,
     482          56 :            arraysize(values));
     483             :   }
     484             : 
     485          56 :   BIND(&fast_c_call);
     486         168 :   GotoIf(IsBigInt64ElementsKind(LoadElementsKind(target)), call_runtime);
     487             :   CallCCopyFastNumberJSArrayElementsToTypedArray(context, source, target,
     488          56 :                                                  source_length, offset);
     489          56 :   Goto(&out);
     490          56 :   BIND(&out);
     491          56 : }
     492             : 
     493         112 : void TypedArrayBuiltinsAssembler::CallCMemmove(TNode<RawPtrT> dest_ptr,
     494             :                                                TNode<RawPtrT> src_ptr,
     495             :                                                TNode<UintPtrT> byte_length) {
     496             :   TNode<ExternalReference> memmove =
     497         112 :       ExternalConstant(ExternalReference::libc_memmove_function());
     498             :   CallCFunction(memmove, MachineType::AnyTagged(),
     499             :                 std::make_pair(MachineType::Pointer(), dest_ptr),
     500             :                 std::make_pair(MachineType::Pointer(), src_ptr),
     501         112 :                 std::make_pair(MachineType::UintPtr(), byte_length));
     502         112 : }
     503             : 
     504          56 : void TypedArrayBuiltinsAssembler::CallCMemcpy(TNode<RawPtrT> dest_ptr,
     505             :                                               TNode<RawPtrT> src_ptr,
     506             :                                               TNode<UintPtrT> byte_length) {
     507             :   TNode<ExternalReference> memcpy =
     508          56 :       ExternalConstant(ExternalReference::libc_memcpy_function());
     509             :   CallCFunction(memcpy, MachineType::AnyTagged(),
     510             :                 std::make_pair(MachineType::Pointer(), dest_ptr),
     511             :                 std::make_pair(MachineType::Pointer(), src_ptr),
     512          56 :                 std::make_pair(MachineType::UintPtr(), byte_length));
     513          56 : }
     514             : 
     515          56 : void TypedArrayBuiltinsAssembler::CallCMemset(TNode<RawPtrT> dest_ptr,
     516             :                                               TNode<IntPtrT> value,
     517             :                                               TNode<UintPtrT> length) {
     518             :   TNode<ExternalReference> memset =
     519          56 :       ExternalConstant(ExternalReference::libc_memset_function());
     520             :   CallCFunction(memset, MachineType::AnyTagged(),
     521             :                 std::make_pair(MachineType::Pointer(), dest_ptr),
     522             :                 std::make_pair(MachineType::IntPtr(), value),
     523          56 :                 std::make_pair(MachineType::UintPtr(), length));
     524          56 : }
     525             : 
     526          56 : void TypedArrayBuiltinsAssembler::
     527             :     CallCCopyFastNumberJSArrayElementsToTypedArray(TNode<Context> context,
     528             :                                                    TNode<JSArray> source,
     529             :                                                    TNode<JSTypedArray> dest,
     530             :                                                    TNode<IntPtrT> source_length,
     531             :                                                    TNode<IntPtrT> offset) {
     532             :   CSA_ASSERT(this,
     533             :              Word32BinaryNot(IsBigInt64ElementsKind(LoadElementsKind(dest))));
     534             :   TNode<ExternalReference> f = ExternalConstant(
     535          56 :       ExternalReference::copy_fast_number_jsarray_elements_to_typed_array());
     536             :   CallCFunction(f, MachineType::AnyTagged(),
     537             :                 std::make_pair(MachineType::AnyTagged(), context),
     538             :                 std::make_pair(MachineType::AnyTagged(), source),
     539             :                 std::make_pair(MachineType::AnyTagged(), dest),
     540             :                 std::make_pair(MachineType::UintPtr(), source_length),
     541          56 :                 std::make_pair(MachineType::UintPtr(), offset));
     542          56 : }
     543             : 
     544          56 : void TypedArrayBuiltinsAssembler::CallCCopyTypedArrayElementsToTypedArray(
     545             :     TNode<JSTypedArray> source, TNode<JSTypedArray> dest,
     546             :     TNode<IntPtrT> source_length, TNode<IntPtrT> offset) {
     547             :   TNode<ExternalReference> f = ExternalConstant(
     548          56 :       ExternalReference::copy_typed_array_elements_to_typed_array());
     549             :   CallCFunction(f, MachineType::AnyTagged(),
     550             :                 std::make_pair(MachineType::AnyTagged(), source),
     551             :                 std::make_pair(MachineType::AnyTagged(), dest),
     552             :                 std::make_pair(MachineType::UintPtr(), source_length),
     553          56 :                 std::make_pair(MachineType::UintPtr(), offset));
     554          56 : }
     555             : 
     556          56 : void TypedArrayBuiltinsAssembler::CallCCopyTypedArrayElementsSlice(
     557             :     TNode<JSTypedArray> source, TNode<JSTypedArray> dest, TNode<IntPtrT> start,
     558             :     TNode<IntPtrT> end) {
     559             :   TNode<ExternalReference> f =
     560          56 :       ExternalConstant(ExternalReference::copy_typed_array_elements_slice());
     561             :   CallCFunction(f, MachineType::AnyTagged(),
     562             :                 std::make_pair(MachineType::AnyTagged(), source),
     563             :                 std::make_pair(MachineType::AnyTagged(), dest),
     564             :                 std::make_pair(MachineType::UintPtr(), start),
     565          56 :                 std::make_pair(MachineType::UintPtr(), end));
     566          56 : }
     567             : 
     568         616 : void TypedArrayBuiltinsAssembler::DispatchTypedArrayByElementsKind(
     569             :     TNode<Word32T> elements_kind, const TypedArraySwitchCase& case_function) {
     570        1232 :   Label next(this), if_unknown_type(this, Label::kDeferred);
     571             : 
     572             :   int32_t elements_kinds[] = {
     573             : #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) TYPE##_ELEMENTS,
     574             :       TYPED_ARRAYS(TYPED_ARRAY_CASE)
     575             : #undef TYPED_ARRAY_CASE
     576         616 :   };
     577             : 
     578             : #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) Label if_##type##array(this);
     579         616 :   TYPED_ARRAYS(TYPED_ARRAY_CASE)
     580             : #undef TYPED_ARRAY_CASE
     581             : 
     582             :   Label* elements_kind_labels[] = {
     583             : #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) &if_##type##array,
     584             :       TYPED_ARRAYS(TYPED_ARRAY_CASE)
     585             : #undef TYPED_ARRAY_CASE
     586         616 :   };
     587             :   STATIC_ASSERT(arraysize(elements_kinds) == arraysize(elements_kind_labels));
     588             : 
     589             :   Switch(elements_kind, &if_unknown_type, elements_kinds, elements_kind_labels,
     590         616 :          arraysize(elements_kinds));
     591             : 
     592             : #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype)   \
     593             :   BIND(&if_##type##array);                          \
     594             :   {                                                 \
     595             :     case_function(TYPE##_ELEMENTS, sizeof(ctype),   \
     596             :                   Context::TYPE##_ARRAY_FUN_INDEX); \
     597             :     Goto(&next);                                    \
     598             :   }
     599        7392 :   TYPED_ARRAYS(TYPED_ARRAY_CASE)
     600             : #undef TYPED_ARRAY_CASE
     601             : 
     602         616 :   BIND(&if_unknown_type);
     603         616 :   Unreachable();
     604             : 
     605         616 :   BIND(&next);
     606         616 : }
     607             : 
     608          56 : TNode<BoolT> TypedArrayBuiltinsAssembler::IsSharedArrayBuffer(
     609             :     TNode<JSArrayBuffer> buffer) {
     610             :   TNode<Uint32T> bitfield =
     611          56 :       LoadObjectField<Uint32T>(buffer, JSArrayBuffer::kBitFieldOffset);
     612          56 :   return IsSetWord32<JSArrayBuffer::IsSharedBit>(bitfield);
     613             : }
     614             : 
     615             : // ES #sec-get-%typedarray%.prototype.set
     616         224 : TF_BUILTIN(TypedArrayPrototypeSet, TypedArrayBuiltinsAssembler) {
     617             :   const char* method_name = "%TypedArray%.prototype.set";
     618             :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
     619             :   CodeStubArguments args(
     620             :       this,
     621         168 :       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount)));
     622             : 
     623          56 :   Label if_source_is_typed_array(this), if_source_is_fast_jsarray(this),
     624          56 :       if_offset_is_out_of_bounds(this, Label::kDeferred),
     625          56 :       if_source_too_large(this, Label::kDeferred),
     626          56 :       if_receiver_is_not_typedarray(this, Label::kDeferred);
     627             : 
     628             :   // Check the receiver is a typed array.
     629          56 :   TNode<Object> receiver = args.GetReceiver();
     630         112 :   GotoIf(TaggedIsSmi(receiver), &if_receiver_is_not_typedarray);
     631         112 :   GotoIfNot(IsJSTypedArray(CAST(receiver)), &if_receiver_is_not_typedarray);
     632             : 
     633             :   // Normalize offset argument (using ToInteger) and handle heap number cases.
     634         112 :   TNode<Object> offset = args.GetOptionalArgumentValue(1, SmiConstant(0));
     635             :   TNode<Number> offset_num =
     636          56 :       ToInteger_Inline(context, offset, kTruncateMinusZero);
     637             : 
     638             :   // Since ToInteger always returns a Smi if the given value is within Smi
     639             :   // range, and the only corner case of -0.0 has already been truncated to 0.0,
     640             :   // we can simply throw unless the offset is a non-negative Smi.
     641             :   // TODO(jgruber): It's an observable spec violation to throw here if
     642             :   // {offset_num} is a positive number outside the Smi range. Per spec, we need
     643             :   // to check for detached buffers and call the observable ToObject/ToLength
     644             :   // operations first.
     645         112 :   GotoIfNot(TaggedIsPositiveSmi(offset_num), &if_offset_is_out_of_bounds);
     646             :   TNode<Smi> offset_smi = CAST(offset_num);
     647             : 
     648             :   // Check the receiver is not detached.
     649          56 :   ThrowIfArrayBufferViewBufferIsDetached(context, CAST(receiver), method_name);
     650             : 
     651             :   // Check the source argument is valid and whether a fast path can be taken.
     652          56 :   Label call_runtime(this);
     653          56 :   TNode<Object> source = args.GetOptionalArgumentValue(0);
     654         112 :   GotoIf(TaggedIsSmi(source), &call_runtime);
     655         112 :   GotoIf(IsJSTypedArray(CAST(source)), &if_source_is_typed_array);
     656          56 :   BranchIfFastJSArray(source, context, &if_source_is_fast_jsarray,
     657          56 :                       &call_runtime);
     658             : 
     659             :   // Fast path for a typed array source argument.
     660          56 :   BIND(&if_source_is_typed_array);
     661             :   {
     662             :     // Check the source argument is not detached.
     663          56 :     ThrowIfArrayBufferViewBufferIsDetached(context, CAST(source), method_name);
     664             : 
     665         112 :     SetTypedArraySource(context, CAST(source), CAST(receiver),
     666             :                         SmiUntag(offset_smi), &call_runtime,
     667          56 :                         &if_source_too_large);
     668         112 :     args.PopAndReturn(UndefinedConstant());
     669             :   }
     670             : 
     671             :   // Fast path for a fast JSArray source argument.
     672          56 :   BIND(&if_source_is_fast_jsarray);
     673             :   {
     674         112 :     SetJSArraySource(context, CAST(source), CAST(receiver),
     675          56 :                      SmiUntag(offset_smi), &call_runtime, &if_source_too_large);
     676         112 :     args.PopAndReturn(UndefinedConstant());
     677             :   }
     678             : 
     679          56 :   BIND(&call_runtime);
     680             :   args.PopAndReturn(CallRuntime(Runtime::kTypedArraySet, context, receiver,
     681          56 :                                 source, offset_smi));
     682             : 
     683          56 :   BIND(&if_offset_is_out_of_bounds);
     684          56 :   ThrowRangeError(context, MessageTemplate::kTypedArraySetOffsetOutOfBounds);
     685             : 
     686          56 :   BIND(&if_source_too_large);
     687          56 :   ThrowRangeError(context, MessageTemplate::kTypedArraySetSourceTooLarge);
     688             : 
     689          56 :   BIND(&if_receiver_is_not_typedarray);
     690          56 :   ThrowTypeError(context, MessageTemplate::kNotTypedArray);
     691          56 : }
     692             : 
     693             : // ES #sec-get-%typedarray%.prototype-@@tostringtag
     694         224 : TF_BUILTIN(TypedArrayPrototypeToStringTag, TypedArrayBuiltinsAssembler) {
     695             :   Node* receiver = Parameter(Descriptor::kReceiver);
     696          56 :   Label if_receiverisheapobject(this), return_undefined(this);
     697         112 :   Branch(TaggedIsSmi(receiver), &return_undefined, &if_receiverisheapobject);
     698             : 
     699             :   // Dispatch on the elements kind, offset by
     700             :   // FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND.
     701             :   size_t const kTypedElementsKindCount = LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND -
     702             :                                          FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND +
     703             :                                          1;
     704             : #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) \
     705             :   Label return_##type##array(this);               \
     706             :   BIND(&return_##type##array);                    \
     707             :   Return(StringConstant(#Type "Array"));
     708        1288 :   TYPED_ARRAYS(TYPED_ARRAY_CASE)
     709             : #undef TYPED_ARRAY_CASE
     710             :   Label* elements_kind_labels[kTypedElementsKindCount] = {
     711             : #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) &return_##type##array,
     712             :       TYPED_ARRAYS(TYPED_ARRAY_CASE)
     713             : #undef TYPED_ARRAY_CASE
     714          56 :   };
     715             :   int32_t elements_kinds[kTypedElementsKindCount] = {
     716             : #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) \
     717             :   TYPE##_ELEMENTS - FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND,
     718             :       TYPED_ARRAYS(TYPED_ARRAY_CASE)
     719             : #undef TYPED_ARRAY_CASE
     720          56 :   };
     721             : 
     722             :   // We offset the dispatch by FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND, so
     723             :   // that this can be turned into a non-sparse table switch for ideal
     724             :   // performance.
     725          56 :   BIND(&if_receiverisheapobject);
     726             :   Node* elements_kind =
     727         224 :       Int32Sub(LoadElementsKind(receiver),
     728         168 :                Int32Constant(FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND));
     729             :   Switch(elements_kind, &return_undefined, elements_kinds, elements_kind_labels,
     730          56 :          kTypedElementsKindCount);
     731             : 
     732          56 :   BIND(&return_undefined);
     733         112 :   Return(UndefinedConstant());
     734          56 : }
     735             : 
     736         168 : void TypedArrayBuiltinsAssembler::GenerateTypedArrayPrototypeIterationMethod(
     737             :     TNode<Context> context, TNode<Object> receiver, const char* method_name,
     738             :     IterationKind kind) {
     739         336 :   Label throw_bad_receiver(this, Label::kDeferred);
     740             : 
     741         336 :   GotoIf(TaggedIsSmi(receiver), &throw_bad_receiver);
     742         336 :   GotoIfNot(IsJSTypedArray(CAST(receiver)), &throw_bad_receiver);
     743             : 
     744             :   // Check if the {receiver}'s JSArrayBuffer was detached.
     745         168 :   ThrowIfArrayBufferViewBufferIsDetached(context, CAST(receiver), method_name);
     746             : 
     747         336 :   Return(CreateArrayIterator(context, receiver, kind));
     748             : 
     749         168 :   BIND(&throw_bad_receiver);
     750         168 :   ThrowTypeError(context, MessageTemplate::kNotTypedArray, method_name);
     751         168 : }
     752             : 
     753             : // ES #sec-%typedarray%.prototype.values
     754         280 : TF_BUILTIN(TypedArrayPrototypeValues, TypedArrayBuiltinsAssembler) {
     755          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
     756          56 :   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
     757          56 :   GenerateTypedArrayPrototypeIterationMethod(context, receiver,
     758             :                                              "%TypedArray%.prototype.values()",
     759          56 :                                              IterationKind::kValues);
     760          56 : }
     761             : 
     762             : // ES #sec-%typedarray%.prototype.entries
     763         280 : TF_BUILTIN(TypedArrayPrototypeEntries, TypedArrayBuiltinsAssembler) {
     764          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
     765          56 :   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
     766          56 :   GenerateTypedArrayPrototypeIterationMethod(context, receiver,
     767             :                                              "%TypedArray%.prototype.entries()",
     768          56 :                                              IterationKind::kEntries);
     769          56 : }
     770             : 
     771             : // ES #sec-%typedarray%.prototype.keys
     772         280 : TF_BUILTIN(TypedArrayPrototypeKeys, TypedArrayBuiltinsAssembler) {
     773          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
     774          56 :   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
     775          56 :   GenerateTypedArrayPrototypeIterationMethod(
     776          56 :       context, receiver, "%TypedArray%.prototype.keys()", IterationKind::kKeys);
     777          56 : }
     778             : 
     779             : // ES6 #sec-%typedarray%.of
     780         280 : TF_BUILTIN(TypedArrayOf, TypedArrayBuiltinsAssembler) {
     781          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
     782             : 
     783             :   // 1. Let len be the actual number of arguments passed to this function.
     784             :   TNode<IntPtrT> length = ChangeInt32ToIntPtr(
     785          56 :       UncheckedCast<Int32T>(Parameter(Descriptor::kJSActualArgumentsCount)));
     786             :   // 2. Let items be the List of arguments passed to this function.
     787             :   CodeStubArguments args(this, length, nullptr, INTPTR_PARAMETERS,
     788          56 :                          CodeStubArguments::ReceiverMode::kHasReceiver);
     789             : 
     790          56 :   Label if_not_constructor(this, Label::kDeferred),
     791          56 :       if_detached(this, Label::kDeferred);
     792             : 
     793             :   // 3. Let C be the this value.
     794             :   // 4. If IsConstructor(C) is false, throw a TypeError exception.
     795          56 :   TNode<Object> receiver = args.GetReceiver();
     796         112 :   GotoIf(TaggedIsSmi(receiver), &if_not_constructor);
     797         112 :   GotoIfNot(IsConstructor(CAST(receiver)), &if_not_constructor);
     798             : 
     799             :   // 5. Let newObj be ? TypedArrayCreate(C, len).
     800             :   TNode<JSTypedArray> new_typed_array = TypedArrayCreateByLength(
     801          56 :       context, receiver, SmiTag(length), "%TypedArray%.of");
     802             : 
     803         112 :   TNode<Word32T> elements_kind = LoadElementsKind(new_typed_array);
     804             : 
     805             :   // 6. Let k be 0.
     806             :   // 7. Repeat, while k < len
     807             :   //  a. Let kValue be items[k].
     808             :   //  b. Let Pk be ! ToString(k).
     809             :   //  c. Perform ? Set(newObj, Pk, kValue, true).
     810             :   //  d. Increase k by 1.
     811          56 :   DispatchTypedArrayByElementsKind(
     812             :       elements_kind,
     813         616 :       [&](ElementsKind kind, int size, int typed_array_fun_index) {
     814             :         TNode<FixedTypedArrayBase> elements =
     815        3696 :             CAST(LoadElements(new_typed_array));
     816        1232 :         BuildFastLoop(
     817        1848 :             IntPtrConstant(0), length,
     818         616 :             [&](Node* index) {
     819        1232 :               TNode<Object> item = args.AtIndex(index, INTPTR_PARAMETERS);
     820        3136 :               TNode<IntPtrT> intptr_index = UncheckedCast<IntPtrT>(index);
     821        1120 :               if (kind == BIGINT64_ELEMENTS || kind == BIGUINT64_ELEMENTS) {
     822        1120 :                 EmitBigTypedArrayElementStore(new_typed_array, elements,
     823        1232 :                                               intptr_index, item, context,
     824        1344 :                                               &if_detached);
     825             :               } else {
     826             :                 Node* value =
     827         504 :                     PrepareValueForWriteToTypedArray(item, kind, context);
     828             : 
     829             :                 // ToNumber may execute JavaScript code, which could detach
     830             :                 // the array's buffer.
     831             :                 Node* buffer = LoadObjectField(new_typed_array,
     832         504 :                                                JSTypedArray::kBufferOffset);
     833        1008 :                 GotoIf(IsDetachedBuffer(buffer), &if_detached);
     834             : 
     835             :                 // GC may move backing store in ToNumber, thus load backing
     836             :                 // store everytime in this loop.
     837             :                 TNode<RawPtrT> backing_store =
     838         504 :                     LoadFixedTypedArrayBackingStore(elements);
     839        1008 :                 StoreElement(backing_store, kind, index, value,
     840         504 :                              INTPTR_PARAMETERS);
     841             :               }
     842         616 :             },
     843         616 :             1, ParameterMode::INTPTR_PARAMETERS, IndexAdvanceMode::kPost);
     844         672 :       });
     845             : 
     846             :   // 8. Return newObj.
     847          56 :   args.PopAndReturn(new_typed_array);
     848             : 
     849          56 :   BIND(&if_not_constructor);
     850          56 :   ThrowTypeError(context, MessageTemplate::kNotConstructor, receiver);
     851             : 
     852          56 :   BIND(&if_detached);
     853             :   ThrowTypeError(context, MessageTemplate::kDetachedOperation,
     854          56 :                  "%TypedArray%.of");
     855          56 : }
     856             : 
     857             : // ES6 #sec-%typedarray%.from
     858         280 : TF_BUILTIN(TypedArrayFrom, TypedArrayBuiltinsAssembler) {
     859          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
     860             : 
     861          56 :   Label check_iterator(this), from_array_like(this), fast_path(this),
     862          56 :       slow_path(this), create_typed_array(this), check_typedarray(this),
     863          56 :       if_not_constructor(this, Label::kDeferred),
     864          56 :       if_map_fn_not_callable(this, Label::kDeferred),
     865          56 :       if_iterator_fn_not_callable(this, Label::kDeferred),
     866          56 :       if_detached(this, Label::kDeferred);
     867             : 
     868             :   CodeStubArguments args(
     869             :       this,
     870         168 :       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount)));
     871          56 :   TNode<Object> source = args.GetOptionalArgumentValue(0);
     872             : 
     873             :   // 5. If thisArg is present, let T be thisArg; else let T be undefined.
     874          56 :   TNode<Object> this_arg = args.GetOptionalArgumentValue(2);
     875             : 
     876             :   // 1. Let C be the this value.
     877             :   // 2. If IsConstructor(C) is false, throw a TypeError exception.
     878          56 :   TNode<Object> receiver = args.GetReceiver();
     879         112 :   GotoIf(TaggedIsSmi(receiver), &if_not_constructor);
     880         112 :   GotoIfNot(IsConstructor(CAST(receiver)), &if_not_constructor);
     881             : 
     882             :   // 3. If mapfn is present and mapfn is not undefined, then
     883          56 :   TNode<Object> map_fn = args.GetOptionalArgumentValue(1);
     884             :   TVARIABLE(BoolT, mapping, Int32FalseConstant());
     885         112 :   GotoIf(IsUndefined(map_fn), &check_typedarray);
     886             : 
     887             :   //  a. If IsCallable(mapfn) is false, throw a TypeError exception.
     888             :   //  b. Let mapping be true.
     889             :   // 4. Else, let mapping be false.
     890         112 :   GotoIf(TaggedIsSmi(map_fn), &if_map_fn_not_callable);
     891         112 :   GotoIfNot(IsCallable(CAST(map_fn)), &if_map_fn_not_callable);
     892             :   mapping = Int32TrueConstant();
     893          56 :   Goto(&check_typedarray);
     894             : 
     895             :   TVARIABLE(Object, final_source);
     896             :   TVARIABLE(Smi, final_length);
     897             : 
     898             :   // We split up this builtin differently to the way it is written in the spec.
     899             :   // We already have great code in the elements accessor for copying from a
     900             :   // JSArray into a TypedArray, so we use that when possible. We only avoid
     901             :   // calling into the elements accessor when we have a mapping function, because
     902             :   // we can't handle that. Here, presence of a mapping function is the slow
     903             :   // path. We also combine the two different loops in the specification
     904             :   // (starting at 7.e and 13) because they are essentially identical. We also
     905             :   // save on code-size this way.
     906             : 
     907             :   // Get the iterator function
     908          56 :   BIND(&check_typedarray);
     909             :   TNode<Object> iterator_fn =
     910         112 :       CAST(GetMethod(context, source, isolate()->factory()->iterator_symbol(),
     911             :                      &from_array_like));
     912         112 :   GotoIf(TaggedIsSmi(iterator_fn), &if_iterator_fn_not_callable);
     913             : 
     914             :   {
     915             :     // TypedArrays have iterators, so normally we would go through the
     916             :     // IterableToList case below, which would convert the TypedArray to a
     917             :     // JSArray (boxing the values if they won't fit in a Smi).
     918             :     //
     919             :     // However, if we can guarantee that the source object has the built-in
     920             :     // iterator and that the %ArrayIteratorPrototype%.next method has not been
     921             :     // overridden, then we know the behavior of the iterator: returning the
     922             :     // values in the TypedArray sequentially from index 0 to length-1.
     923             :     //
     924             :     // In this case, we can avoid creating the intermediate array and the
     925             :     // associated HeapNumbers, and use the fast path in TypedArrayCopyElements
     926             :     // which uses the same ordering as the default iterator.
     927             :     //
     928             :     // Drop through to the default check_iterator behavior if any of these
     929             :     // checks fail.
     930             : 
     931             :     // Check that the source is a TypedArray
     932         112 :     GotoIf(TaggedIsSmi(source), &check_iterator);
     933         112 :     GotoIfNot(IsJSTypedArray(CAST(source)), &check_iterator);
     934             :     TNode<JSArrayBuffer> source_buffer =
     935          56 :         LoadJSArrayBufferViewBuffer(CAST(source));
     936         112 :     GotoIf(IsDetachedBuffer(source_buffer), &check_iterator);
     937             : 
     938             :     // Check that the iterator function is Builtins::kTypedArrayPrototypeValues
     939         112 :     GotoIfNot(IsJSFunction(CAST(iterator_fn)), &check_iterator);
     940             :     TNode<SharedFunctionInfo> shared_info = LoadObjectField<SharedFunctionInfo>(
     941             :         CAST(iterator_fn), JSFunction::kSharedFunctionInfoOffset);
     942          56 :     GotoIfNot(
     943             :         WordEqual(LoadObjectField(shared_info,
     944             :                                   SharedFunctionInfo::kFunctionDataOffset),
     945             :                   SmiConstant(Builtins::kTypedArrayPrototypeValues)),
     946          56 :         &check_iterator);
     947             :     // Check that the ArrayIterator prototype's "next" method hasn't been
     948             :     // overridden
     949             :     TNode<PropertyCell> protector_cell =
     950          56 :         CAST(LoadRoot(RootIndex::kArrayIteratorProtector));
     951          56 :     GotoIfNot(
     952             :         WordEqual(LoadObjectField(protector_cell, PropertyCell::kValueOffset),
     953          56 :                   SmiConstant(Isolate::kProtectorValid)),
     954          56 :         &check_iterator);
     955             : 
     956             :     // Source is a TypedArray with unmodified iterator behavior. Use the
     957             :     // source object directly, taking advantage of the special-case code in
     958             :     // TypedArrayCopyElements
     959          56 :     final_length = LoadJSTypedArrayLength(CAST(source));
     960             :     final_source = source;
     961          56 :     Goto(&create_typed_array);
     962             :   }
     963             : 
     964          56 :   BIND(&check_iterator);
     965             :   {
     966             :     // 6. Let usingIterator be ? GetMethod(source, @@iterator).
     967         112 :     GotoIfNot(IsCallable(CAST(iterator_fn)), &if_iterator_fn_not_callable);
     968             : 
     969             :     // We are using the iterator.
     970          56 :     Label if_length_not_smi(this, Label::kDeferred);
     971             :     // 7. If usingIterator is not undefined, then
     972             :     //  a. Let values be ? IterableToList(source, usingIterator).
     973             :     //  b. Let len be the number of elements in values.
     974          56 :     TNode<JSArray> values = CAST(
     975             :         CallBuiltin(Builtins::kIterableToList, context, source, iterator_fn));
     976             : 
     977             :     // This is not a spec'd limit, so it doesn't particularly matter when we
     978             :     // throw the range error for typed array length > MaxSmi.
     979         112 :     TNode<Object> raw_length = LoadJSArrayLength(values);
     980         112 :     GotoIfNot(TaggedIsSmi(raw_length), &if_length_not_smi);
     981             : 
     982             :     final_length = CAST(raw_length);
     983             :     final_source = values;
     984          56 :     Goto(&create_typed_array);
     985             : 
     986          56 :     BIND(&if_length_not_smi);
     987             :     ThrowRangeError(context, MessageTemplate::kInvalidTypedArrayLength,
     988          56 :                     raw_length);
     989             :   }
     990             : 
     991          56 :   BIND(&from_array_like);
     992             :   {
     993             :     // TODO(7881): support larger-than-smi typed array lengths
     994          56 :     Label if_length_not_smi(this, Label::kDeferred);
     995             :     final_source = source;
     996             : 
     997             :     // 10. Let len be ? ToLength(? Get(arrayLike, "length")).
     998             :     TNode<Object> raw_length =
     999         112 :         GetProperty(context, final_source.value(), LengthStringConstant());
    1000          56 :     final_length = ToSmiLength(context, raw_length, &if_length_not_smi);
    1001          56 :     Goto(&create_typed_array);
    1002             : 
    1003          56 :     BIND(&if_length_not_smi);
    1004             :     ThrowRangeError(context, MessageTemplate::kInvalidTypedArrayLength,
    1005          56 :                     raw_length);
    1006             :   }
    1007             : 
    1008             :   TVARIABLE(JSTypedArray, target_obj);
    1009             : 
    1010          56 :   BIND(&create_typed_array);
    1011             :   {
    1012             :     // 7c/11. Let targetObj be ? TypedArrayCreate(C, «len»).
    1013          56 :     target_obj = TypedArrayCreateByLength(
    1014             :         context, receiver, final_length.value(), "%TypedArray%.from");
    1015             : 
    1016          56 :     Branch(mapping.value(), &slow_path, &fast_path);
    1017             :   }
    1018             : 
    1019          56 :   BIND(&fast_path);
    1020             :   {
    1021          56 :     Label done(this);
    1022         168 :     GotoIf(SmiEqual(final_length.value(), SmiConstant(0)), &done);
    1023             : 
    1024             :     CallRuntime(Runtime::kTypedArrayCopyElements, context, target_obj.value(),
    1025             :                 final_source.value(), final_length.value());
    1026          56 :     Goto(&done);
    1027             : 
    1028          56 :     BIND(&done);
    1029          56 :     args.PopAndReturn(target_obj.value());
    1030             :   }
    1031             : 
    1032          56 :   BIND(&slow_path);
    1033         112 :   TNode<Word32T> elements_kind = LoadElementsKind(target_obj.value());
    1034             : 
    1035             :   // 7e/13 : Copy the elements
    1036          56 :   TNode<FixedTypedArrayBase> elements = CAST(LoadElements(target_obj.value()));
    1037          56 :   BuildFastLoop(
    1038         112 :       SmiConstant(0), final_length.value(),
    1039          56 :       [&](Node* index) {
    1040             :         TNode<Object> const k_value =
    1041         616 :             GetProperty(context, final_source.value(), index);
    1042             : 
    1043             :         TNode<Object> const mapped_value =
    1044         336 :             CAST(CallJS(CodeFactory::Call(isolate()), context, map_fn, this_arg,
    1045             :                         k_value, index));
    1046             : 
    1047         112 :         TNode<IntPtrT> intptr_index = SmiUntag(index);
    1048         112 :         DispatchTypedArrayByElementsKind(
    1049          56 :             elements_kind,
    1050         616 :             [&](ElementsKind kind, int size, int typed_array_fun_index) {
    1051         616 :               if (kind == BIGINT64_ELEMENTS || kind == BIGUINT64_ELEMENTS) {
    1052        1288 :                 EmitBigTypedArrayElementStore(target_obj.value(), elements,
    1053         616 :                                               intptr_index, mapped_value,
    1054        3416 :                                               context, &if_detached);
    1055             :               } else {
    1056        1008 :                 Node* const final_value = PrepareValueForWriteToTypedArray(
    1057         504 :                     mapped_value, kind, context);
    1058             : 
    1059             :                 // ToNumber may execute JavaScript code, which could detach
    1060             :                 // the array's buffer.
    1061             :                 Node* buffer = LoadObjectField(target_obj.value(),
    1062         504 :                                                JSTypedArray::kBufferOffset);
    1063        1008 :                 GotoIf(IsDetachedBuffer(buffer), &if_detached);
    1064             : 
    1065             :                 // GC may move backing store in map_fn, thus load backing
    1066             :                 // store in each iteration of this loop.
    1067             :                 TNode<RawPtrT> backing_store =
    1068         504 :                     LoadFixedTypedArrayBackingStore(elements);
    1069        1008 :                 StoreElement(backing_store, kind, index, final_value,
    1070         504 :                              SMI_PARAMETERS);
    1071             :               }
    1072         672 :             });
    1073          56 :       },
    1074          56 :       1, ParameterMode::SMI_PARAMETERS, IndexAdvanceMode::kPost);
    1075             : 
    1076          56 :   args.PopAndReturn(target_obj.value());
    1077             : 
    1078          56 :   BIND(&if_not_constructor);
    1079          56 :   ThrowTypeError(context, MessageTemplate::kNotConstructor, receiver);
    1080             : 
    1081          56 :   BIND(&if_map_fn_not_callable);
    1082          56 :   ThrowTypeError(context, MessageTemplate::kCalledNonCallable, map_fn);
    1083             : 
    1084          56 :   BIND(&if_iterator_fn_not_callable);
    1085          56 :   ThrowTypeError(context, MessageTemplate::kIteratorSymbolNonCallable);
    1086             : 
    1087          56 :   BIND(&if_detached);
    1088             :   ThrowTypeError(context, MessageTemplate::kDetachedOperation,
    1089          56 :                  "%TypedArray%.from");
    1090          56 : }
    1091             : 
    1092             : #undef V8_TYPED_ARRAY_MAX_SIZE_IN_HEAP
    1093             : 
    1094             : }  // namespace internal
    1095       59456 : }  // namespace v8

Generated by: LCOV version 1.10