LCOV - code coverage report
Current view: top level - src/builtins - builtins-typed-array-gen.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 501 513 97.7 %
Date: 2019-03-21 Functions: 99 101 98.0 %

          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         168 :   StoreObjectFieldNoWriteBarrier(holder, JSArrayBufferView::kByteOffsetOffset,
      60             :                                  byte_offset,
      61         168 :                                  MachineType::PointerRepresentation());
      62         168 :   StoreObjectFieldNoWriteBarrier(holder, JSArrayBufferView::kByteLengthOffset,
      63             :                                  byte_length,
      64         168 :                                  MachineType::PointerRepresentation());
      65         840 :   for (int offset = JSTypedArray::kHeaderSize;
      66         840 :        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         224 :   StoreObjectFieldNoWriteBarrier(buffer, JSArray::kPropertiesOrHashOffset,
      86         112 :                                  empty_fixed_array);
      87         224 :   StoreObjectFieldNoWriteBarrier(buffer, JSArray::kElementsOffset,
      88         112 :                                  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             :         buffer, JSArrayBuffer::kOptionalPaddingOffset, Int32Constant(0),
      99             :         MachineRepresentation::kWord32);
     100             :   }
     101             :   int32_t bitfield_value = (1 << JSArrayBuffer::IsExternalBit::kShift) |
     102         112 :                            (1 << JSArrayBuffer::IsDetachableBit::kShift);
     103         112 :   StoreObjectFieldNoWriteBarrier(buffer, JSArrayBuffer::kBitFieldOffset,
     104         224 :                                  Int32Constant(bitfield_value),
     105         112 :                                  MachineRepresentation::kWord32);
     106             : 
     107         112 :   StoreObjectFieldNoWriteBarrier(buffer, JSArrayBuffer::kByteLengthOffset,
     108             :                                  byte_length,
     109         112 :                                  MachineType::PointerRepresentation());
     110         224 :   StoreObjectFieldNoWriteBarrier(buffer, JSArrayBuffer::kBackingStoreOffset,
     111         224 :                                  IntPtrConstant(0),
     112         112 :                                  MachineType::PointerRepresentation());
     113         560 :   for (int offset = JSArrayBuffer::kHeaderSize;
     114         560 :        offset < JSArrayBuffer::kSizeWithEmbedderFields; offset += kTaggedSize) {
     115         448 :     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         112 :   TNode<Object> elements;
     131             : 
     132         224 :   if (UnalignedLoadSupported(MachineRepresentation::kFloat64) &&
     133         112 :       UnalignedStoreSupported(MachineRepresentation::kFloat64)) {
     134         112 :     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         112 :   StoreObjectFieldNoWriteBarrier(
     142         112 :       elements, FixedTypedArrayBase::kBasePointerOffset, elements);
     143         224 :   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        1568 :   TNode<FixedArrayBase> elements = LoadElements(typed_array);
     153             :   CSA_ASSERT(this, IsFixedTypedArray(elements));
     154        1568 :   return LoadFixedTypedArrayBackingStore(CAST(elements));
     155             : }
     156             : 
     157         280 : TF_BUILTIN(TypedArrayBaseConstructor, TypedArrayBuiltinsAssembler) {
     158          56 :   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         448 : TF_BUILTIN(TypedArrayConstructor, TypedArrayBuiltinsAssembler) {
     165          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
     166          56 :   TNode<JSFunction> target = CAST(Parameter(Descriptor::kJSTarget));
     167          56 :   TNode<Object> new_target = CAST(Parameter(Descriptor::kJSNewTarget));
     168             :   Node* argc =
     169          56 :       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
     170          56 :   CodeStubArguments args(this, argc);
     171          56 :   Node* arg1 = args.GetOptionalArgumentValue(0);
     172          56 :   Node* arg2 = args.GetOptionalArgumentValue(1);
     173          56 :   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         112 :   Label throwtypeerror(this, Label::kDeferred);
     179          56 :   GotoIf(IsUndefined(new_target), &throwtypeerror);
     180             : 
     181         112 :   Node* result = CallBuiltin(Builtins::kCreateTypedArray, context, target,
     182         168 :                              new_target, arg1, arg2, arg3);
     183          56 :   args.PopAndReturn(result);
     184             : 
     185          56 :   BIND(&throwtypeerror);
     186             :   {
     187             :     TNode<String> name =
     188          56 :         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         336 : TF_BUILTIN(TypedArrayPrototypeByteLength, TypedArrayBuiltinsAssembler) {
     195          56 :   const char* const kMethodName = "get TypedArray.prototype.byteLength";
     196          56 :   Node* context = Parameter(Descriptor::kContext);
     197          56 :   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         112 :       [=] { return LoadJSArrayBufferViewByteLength(CAST(receiver)); });
     208          56 :   Return(ChangeUintPtrToTagged(byte_length));
     209          56 : }
     210             : 
     211             : // ES6 #sec-get-%typedarray%.prototype.byteoffset
     212         336 : TF_BUILTIN(TypedArrayPrototypeByteOffset, TypedArrayBuiltinsAssembler) {
     213          56 :   const char* const kMethodName = "get TypedArray.prototype.byteOffset";
     214          56 :   Node* context = Parameter(Descriptor::kContext);
     215          56 :   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         112 :       [=] { return LoadJSArrayBufferViewByteOffset(CAST(receiver)); });
     226          56 :   Return(ChangeUintPtrToTagged(byte_offset));
     227          56 : }
     228             : 
     229             : // ES6 #sec-get-%typedarray%.prototype.length
     230         336 : TF_BUILTIN(TypedArrayPrototypeLength, TypedArrayBuiltinsAssembler) {
     231          56 :   const char* const kMethodName = "get TypedArray.prototype.length";
     232          56 :   Node* context = Parameter(Descriptor::kContext);
     233          56 :   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         112 :       [=] { return LoadJSTypedArrayLength(CAST(receiver)); });
     244          56 :   Return(length);
     245          56 : }
     246             : 
     247         112 : TNode<Word32T> TypedArrayBuiltinsAssembler::IsUint8ElementsKind(
     248             :     TNode<Word32T> kind) {
     249         224 :   return Word32Or(Word32Equal(kind, Int32Constant(UINT8_ELEMENTS)),
     250         336 :                   Word32Equal(kind, Int32Constant(UINT8_CLAMPED_ELEMENTS)));
     251             : }
     252             : 
     253         280 : TNode<Word32T> TypedArrayBuiltinsAssembler::IsBigInt64ElementsKind(
     254             :     TNode<Word32T> kind) {
     255         560 :   return Word32Or(Word32Equal(kind, Int32Constant(BIGINT64_ELEMENTS)),
     256         840 :                   Word32Equal(kind, Int32Constant(BIGUINT64_ELEMENTS)));
     257             : }
     258             : 
     259         112 : TNode<IntPtrT> TypedArrayBuiltinsAssembler::GetTypedArrayElementSize(
     260             :     TNode<Word32T> elements_kind) {
     261         224 :   TVARIABLE(IntPtrT, element_size);
     262             : 
     263         224 :   DispatchTypedArrayByElementsKind(
     264             :       elements_kind,
     265        1232 :       [&](ElementsKind el_kind, int size, int typed_array_fun_index) {
     266        1232 :         element_size = IntPtrConstant(size);
     267        1344 :       });
     268             : 
     269         224 :   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         336 :   TVARIABLE(UintPtrT, var_size_log2);
     277         336 :   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        3696 :         var_size_log2 = UintPtrConstant(ElementsKindToShiftSize(kind));
     285             : 
     286        1848 :         Handle<Map> map(roots.MapForFixedTypedArray(kind), isolate());
     287        1848 :         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         448 :   TVARIABLE(IntPtrT, context_slot);
     297         224 :   TNode<Word32T> elements_kind = LoadElementsKind(exemplar);
     298             : 
     299         448 :   DispatchTypedArrayByElementsKind(
     300             :       elements_kind,
     301        2464 :       [&](ElementsKind el_kind, int size, int typed_array_function_index) {
     302        2464 :         context_slot = IntPtrConstant(typed_array_function_index);
     303        2688 :       });
     304             : 
     305         448 :   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         112 :   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         112 :   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         112 :   TVARIABLE(Object, var_result);
     342             : 
     343          56 :   TNode<Object> buffer = LoadObjectField(array, JSTypedArray::kBufferOffset);
     344          56 :   GotoIf(IsDetachedBuffer(buffer), &call_runtime);
     345             :   TNode<UintPtrT> backing_store = LoadObjectField<UintPtrT>(
     346          56 :       CAST(buffer), JSArrayBuffer::kBackingStoreOffset);
     347          56 :   GotoIf(WordEqual(backing_store, IntPtrConstant(0)), &call_runtime);
     348          56 :   var_result = buffer;
     349          56 :   Goto(&done);
     350             : 
     351          56 :   BIND(&call_runtime);
     352             :   {
     353          56 :     var_result = CallRuntime(Runtime::kTypedArrayGetBuffer, context, array);
     354          56 :     Goto(&done);
     355             :   }
     356             : 
     357          56 :   BIND(&done);
     358         112 :   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          56 :   TNode<IntPtrT> source_length = SmiUntag(LoadJSTypedArrayLength(source));
     387          56 :   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          56 :   TNode<Word32T> source_el_kind = LoadElementsKind(source);
     399          56 :   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          56 :   TNode<IntPtrT> source_byte_length = IntPtrMul(source_length, source_el_size);
     408             :   CSA_ASSERT(this,
     409             :              UintPtrGreaterThanOrEqual(source_byte_length, IntPtrConstant(0)));
     410             : 
     411         112 :   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          56 :   GotoIf(Word32Equal(source_el_kind, target_el_kind), &call_memmove);
     416          56 :   GotoIfNot(IsUint8ElementsKind(source_el_kind), &fast_c_call);
     417          56 :   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         224 :                           IsBigInt64ElementsKind(target_el_kind)),
     435          56 :            &exception);
     436             : 
     437          56 :     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          56 :   TNode<IntPtrT> source_length = SmiUntag(LoadFastJSArrayLength(source));
     458          56 :   TNode<IntPtrT> target_length = SmiUntag(LoadJSTypedArrayLength(target));
     459             : 
     460             :   // Maybe out of bounds?
     461         112 :   GotoIf(IntPtrGreaterThan(IntPtrAdd(source_length, offset), target_length),
     462          56 :          if_source_too_large);
     463             : 
     464             :   // Nothing to do if {source} is empty.
     465         112 :   Label out(this), fast_c_call(this);
     466          56 :   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          56 :     Switch(source_elements_kind, call_runtime, values, labels,
     482          56 :            arraysize(values));
     483             :   }
     484             : 
     485          56 :   BIND(&fast_c_call);
     486          56 :   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         112 :   CallCFunction3(MachineType::AnyTagged(), MachineType::Pointer(),
     499             :                  MachineType::Pointer(), MachineType::UintPtr(), memmove,
     500         112 :                  dest_ptr, src_ptr, byte_length);
     501         112 : }
     502             : 
     503          56 : void TypedArrayBuiltinsAssembler::CallCMemcpy(TNode<RawPtrT> dest_ptr,
     504             :                                               TNode<RawPtrT> src_ptr,
     505             :                                               TNode<UintPtrT> byte_length) {
     506             :   TNode<ExternalReference> memcpy =
     507          56 :       ExternalConstant(ExternalReference::libc_memcpy_function());
     508          56 :   CallCFunction3(MachineType::AnyTagged(), MachineType::Pointer(),
     509             :                  MachineType::Pointer(), MachineType::UintPtr(), memcpy,
     510          56 :                  dest_ptr, src_ptr, byte_length);
     511          56 : }
     512             : 
     513          56 : void TypedArrayBuiltinsAssembler::CallCMemset(TNode<RawPtrT> dest_ptr,
     514             :                                               TNode<IntPtrT> value,
     515             :                                               TNode<UintPtrT> length) {
     516             :   TNode<ExternalReference> memset =
     517          56 :       ExternalConstant(ExternalReference::libc_memset_function());
     518          56 :   CallCFunction3(MachineType::AnyTagged(), MachineType::Pointer(),
     519             :                  MachineType::IntPtr(), MachineType::UintPtr(), memset,
     520          56 :                  dest_ptr, value, length);
     521          56 : }
     522             : 
     523          56 : void TypedArrayBuiltinsAssembler::
     524             :     CallCCopyFastNumberJSArrayElementsToTypedArray(TNode<Context> context,
     525             :                                                    TNode<JSArray> source,
     526             :                                                    TNode<JSTypedArray> dest,
     527             :                                                    TNode<IntPtrT> source_length,
     528             :                                                    TNode<IntPtrT> offset) {
     529             :   CSA_ASSERT(this,
     530             :              Word32BinaryNot(IsBigInt64ElementsKind(LoadElementsKind(dest))));
     531             :   TNode<ExternalReference> f = ExternalConstant(
     532          56 :       ExternalReference::copy_fast_number_jsarray_elements_to_typed_array());
     533          56 :   CallCFunction5(MachineType::AnyTagged(), MachineType::AnyTagged(),
     534             :                  MachineType::AnyTagged(), MachineType::AnyTagged(),
     535             :                  MachineType::UintPtr(), MachineType::UintPtr(), f, context,
     536          56 :                  source, dest, source_length, offset);
     537          56 : }
     538             : 
     539          56 : void TypedArrayBuiltinsAssembler::CallCCopyTypedArrayElementsToTypedArray(
     540             :     TNode<JSTypedArray> source, TNode<JSTypedArray> dest,
     541             :     TNode<IntPtrT> source_length, TNode<IntPtrT> offset) {
     542             :   TNode<ExternalReference> f = ExternalConstant(
     543          56 :       ExternalReference::copy_typed_array_elements_to_typed_array());
     544          56 :   CallCFunction4(MachineType::AnyTagged(), MachineType::AnyTagged(),
     545             :                  MachineType::AnyTagged(), MachineType::UintPtr(),
     546             :                  MachineType::UintPtr(), f, source, dest, source_length,
     547          56 :                  offset);
     548          56 : }
     549             : 
     550          56 : void TypedArrayBuiltinsAssembler::CallCCopyTypedArrayElementsSlice(
     551             :     TNode<JSTypedArray> source, TNode<JSTypedArray> dest, TNode<IntPtrT> start,
     552             :     TNode<IntPtrT> end) {
     553             :   TNode<ExternalReference> f =
     554          56 :       ExternalConstant(ExternalReference::copy_typed_array_elements_slice());
     555          56 :   CallCFunction4(MachineType::AnyTagged(), MachineType::AnyTagged(),
     556             :                  MachineType::AnyTagged(), MachineType::UintPtr(),
     557          56 :                  MachineType::UintPtr(), f, source, dest, start, end);
     558          56 : }
     559             : 
     560         616 : void TypedArrayBuiltinsAssembler::DispatchTypedArrayByElementsKind(
     561             :     TNode<Word32T> elements_kind, const TypedArraySwitchCase& case_function) {
     562        1232 :   Label next(this), if_unknown_type(this, Label::kDeferred);
     563             : 
     564             :   int32_t elements_kinds[] = {
     565             : #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) TYPE##_ELEMENTS,
     566             :       TYPED_ARRAYS(TYPED_ARRAY_CASE)
     567             : #undef TYPED_ARRAY_CASE
     568         616 :   };
     569             : 
     570             : #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) Label if_##type##array(this);
     571        1232 :   TYPED_ARRAYS(TYPED_ARRAY_CASE)
     572             : #undef TYPED_ARRAY_CASE
     573             : 
     574             :   Label* elements_kind_labels[] = {
     575             : #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) &if_##type##array,
     576             :       TYPED_ARRAYS(TYPED_ARRAY_CASE)
     577             : #undef TYPED_ARRAY_CASE
     578         616 :   };
     579             :   STATIC_ASSERT(arraysize(elements_kinds) == arraysize(elements_kind_labels));
     580             : 
     581         616 :   Switch(elements_kind, &if_unknown_type, elements_kinds, elements_kind_labels,
     582         616 :          arraysize(elements_kinds));
     583             : 
     584             : #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype)   \
     585             :   BIND(&if_##type##array);                          \
     586             :   {                                                 \
     587             :     case_function(TYPE##_ELEMENTS, sizeof(ctype),   \
     588             :                   Context::TYPE##_ARRAY_FUN_INDEX); \
     589             :     Goto(&next);                                    \
     590             :   }
     591         616 :   TYPED_ARRAYS(TYPED_ARRAY_CASE)
     592             : #undef TYPED_ARRAY_CASE
     593             : 
     594         616 :   BIND(&if_unknown_type);
     595         616 :   Unreachable();
     596             : 
     597         616 :   BIND(&next);
     598         616 : }
     599             : 
     600          56 : TNode<BoolT> TypedArrayBuiltinsAssembler::IsSharedArrayBuffer(
     601             :     TNode<JSArrayBuffer> buffer) {
     602             :   TNode<Uint32T> bitfield =
     603          56 :       LoadObjectField<Uint32T>(buffer, JSArrayBuffer::kBitFieldOffset);
     604          56 :   return IsSetWord32<JSArrayBuffer::IsSharedBit>(bitfield);
     605             : }
     606             : 
     607             : // ES #sec-get-%typedarray%.prototype.set
     608         336 : TF_BUILTIN(TypedArrayPrototypeSet, TypedArrayBuiltinsAssembler) {
     609          56 :   const char* method_name = "%TypedArray%.prototype.set";
     610          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
     611             :   CodeStubArguments args(
     612             :       this,
     613          56 :       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount)));
     614             : 
     615         112 :   Label if_source_is_typed_array(this), if_source_is_fast_jsarray(this),
     616         112 :       if_offset_is_out_of_bounds(this, Label::kDeferred),
     617         112 :       if_source_too_large(this, Label::kDeferred),
     618         112 :       if_receiver_is_not_typedarray(this, Label::kDeferred);
     619             : 
     620             :   // Check the receiver is a typed array.
     621          56 :   TNode<Object> receiver = args.GetReceiver();
     622          56 :   GotoIf(TaggedIsSmi(receiver), &if_receiver_is_not_typedarray);
     623          56 :   GotoIfNot(IsJSTypedArray(CAST(receiver)), &if_receiver_is_not_typedarray);
     624             : 
     625             :   // Normalize offset argument (using ToInteger) and handle heap number cases.
     626          56 :   TNode<Object> offset = args.GetOptionalArgumentValue(1, SmiConstant(0));
     627             :   TNode<Number> offset_num =
     628          56 :       ToInteger_Inline(context, offset, kTruncateMinusZero);
     629             : 
     630             :   // Since ToInteger always returns a Smi if the given value is within Smi
     631             :   // range, and the only corner case of -0.0 has already been truncated to 0.0,
     632             :   // we can simply throw unless the offset is a non-negative Smi.
     633             :   // TODO(jgruber): It's an observable spec violation to throw here if
     634             :   // {offset_num} is a positive number outside the Smi range. Per spec, we need
     635             :   // to check for detached buffers and call the observable ToObject/ToLength
     636             :   // operations first.
     637          56 :   GotoIfNot(TaggedIsPositiveSmi(offset_num), &if_offset_is_out_of_bounds);
     638          56 :   TNode<Smi> offset_smi = CAST(offset_num);
     639             : 
     640             :   // Check the receiver is not detached.
     641          56 :   ThrowIfArrayBufferViewBufferIsDetached(context, CAST(receiver), method_name);
     642             : 
     643             :   // Check the source argument is valid and whether a fast path can be taken.
     644         112 :   Label call_runtime(this);
     645          56 :   TNode<Object> source = args.GetOptionalArgumentValue(0);
     646          56 :   GotoIf(TaggedIsSmi(source), &call_runtime);
     647          56 :   GotoIf(IsJSTypedArray(CAST(source)), &if_source_is_typed_array);
     648          56 :   BranchIfFastJSArray(source, context, &if_source_is_fast_jsarray,
     649          56 :                       &call_runtime);
     650             : 
     651             :   // Fast path for a typed array source argument.
     652          56 :   BIND(&if_source_is_typed_array);
     653             :   {
     654             :     // Check the source argument is not detached.
     655          56 :     ThrowIfArrayBufferViewBufferIsDetached(context, CAST(source), method_name);
     656             : 
     657         112 :     SetTypedArraySource(context, CAST(source), CAST(receiver),
     658             :                         SmiUntag(offset_smi), &call_runtime,
     659          56 :                         &if_source_too_large);
     660          56 :     args.PopAndReturn(UndefinedConstant());
     661             :   }
     662             : 
     663             :   // Fast path for a fast JSArray source argument.
     664          56 :   BIND(&if_source_is_fast_jsarray);
     665             :   {
     666         112 :     SetJSArraySource(context, CAST(source), CAST(receiver),
     667          56 :                      SmiUntag(offset_smi), &call_runtime, &if_source_too_large);
     668          56 :     args.PopAndReturn(UndefinedConstant());
     669             :   }
     670             : 
     671          56 :   BIND(&call_runtime);
     672         112 :   args.PopAndReturn(CallRuntime(Runtime::kTypedArraySet, context, receiver,
     673         168 :                                 source, offset_smi));
     674             : 
     675          56 :   BIND(&if_offset_is_out_of_bounds);
     676          56 :   ThrowRangeError(context, MessageTemplate::kTypedArraySetOffsetOutOfBounds);
     677             : 
     678          56 :   BIND(&if_source_too_large);
     679          56 :   ThrowRangeError(context, MessageTemplate::kTypedArraySetSourceTooLarge);
     680             : 
     681          56 :   BIND(&if_receiver_is_not_typedarray);
     682          56 :   ThrowTypeError(context, MessageTemplate::kNotTypedArray);
     683          56 : }
     684             : 
     685             : // ES #sec-get-%typedarray%.prototype-@@tostringtag
     686         280 : TF_BUILTIN(TypedArrayPrototypeToStringTag, TypedArrayBuiltinsAssembler) {
     687          56 :   Node* receiver = Parameter(Descriptor::kReceiver);
     688         112 :   Label if_receiverisheapobject(this), return_undefined(this);
     689          56 :   Branch(TaggedIsSmi(receiver), &return_undefined, &if_receiverisheapobject);
     690             : 
     691             :   // Dispatch on the elements kind, offset by
     692             :   // FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND.
     693             :   size_t const kTypedElementsKindCount = LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND -
     694             :                                          FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND +
     695          56 :                                          1;
     696             : #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) \
     697             :   Label return_##type##array(this);               \
     698             :   BIND(&return_##type##array);                    \
     699             :   Return(StringConstant(#Type "Array"));
     700         112 :   TYPED_ARRAYS(TYPED_ARRAY_CASE)
     701             : #undef TYPED_ARRAY_CASE
     702             :   Label* elements_kind_labels[kTypedElementsKindCount] = {
     703             : #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) &return_##type##array,
     704             :       TYPED_ARRAYS(TYPED_ARRAY_CASE)
     705             : #undef TYPED_ARRAY_CASE
     706          56 :   };
     707             :   int32_t elements_kinds[kTypedElementsKindCount] = {
     708             : #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) \
     709             :   TYPE##_ELEMENTS - FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND,
     710             :       TYPED_ARRAYS(TYPED_ARRAY_CASE)
     711             : #undef TYPED_ARRAY_CASE
     712          56 :   };
     713             : 
     714             :   // We offset the dispatch by FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND, so
     715             :   // that this can be turned into a non-sparse table switch for ideal
     716             :   // performance.
     717          56 :   BIND(&if_receiverisheapobject);
     718             :   Node* elements_kind =
     719         224 :       Int32Sub(LoadElementsKind(receiver),
     720         280 :                Int32Constant(FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND));
     721          56 :   Switch(elements_kind, &return_undefined, elements_kinds, elements_kind_labels,
     722          56 :          kTypedElementsKindCount);
     723             : 
     724          56 :   BIND(&return_undefined);
     725          56 :   Return(UndefinedConstant());
     726          56 : }
     727             : 
     728         168 : void TypedArrayBuiltinsAssembler::GenerateTypedArrayPrototypeIterationMethod(
     729             :     TNode<Context> context, TNode<Object> receiver, const char* method_name,
     730             :     IterationKind kind) {
     731         336 :   Label throw_bad_receiver(this, Label::kDeferred);
     732             : 
     733         168 :   GotoIf(TaggedIsSmi(receiver), &throw_bad_receiver);
     734         168 :   GotoIfNot(IsJSTypedArray(CAST(receiver)), &throw_bad_receiver);
     735             : 
     736             :   // Check if the {receiver}'s JSArrayBuffer was detached.
     737         168 :   ThrowIfArrayBufferViewBufferIsDetached(context, CAST(receiver), method_name);
     738             : 
     739         168 :   Return(CreateArrayIterator(context, receiver, kind));
     740             : 
     741         168 :   BIND(&throw_bad_receiver);
     742         168 :   ThrowTypeError(context, MessageTemplate::kNotTypedArray, method_name);
     743         168 : }
     744             : 
     745             : // ES #sec-%typedarray%.prototype.values
     746         336 : TF_BUILTIN(TypedArrayPrototypeValues, TypedArrayBuiltinsAssembler) {
     747          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
     748          56 :   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
     749          56 :   GenerateTypedArrayPrototypeIterationMethod(context, receiver,
     750             :                                              "%TypedArray%.prototype.values()",
     751          56 :                                              IterationKind::kValues);
     752          56 : }
     753             : 
     754             : // ES #sec-%typedarray%.prototype.entries
     755         336 : TF_BUILTIN(TypedArrayPrototypeEntries, TypedArrayBuiltinsAssembler) {
     756          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
     757          56 :   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
     758          56 :   GenerateTypedArrayPrototypeIterationMethod(context, receiver,
     759             :                                              "%TypedArray%.prototype.entries()",
     760          56 :                                              IterationKind::kEntries);
     761          56 : }
     762             : 
     763             : // ES #sec-%typedarray%.prototype.keys
     764         336 : TF_BUILTIN(TypedArrayPrototypeKeys, TypedArrayBuiltinsAssembler) {
     765          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
     766          56 :   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
     767          56 :   GenerateTypedArrayPrototypeIterationMethod(
     768          56 :       context, receiver, "%TypedArray%.prototype.keys()", IterationKind::kKeys);
     769          56 : }
     770             : 
     771             : // ES6 #sec-%typedarray%.of
     772         336 : TF_BUILTIN(TypedArrayOf, TypedArrayBuiltinsAssembler) {
     773          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
     774             : 
     775             :   // 1. Let len be the actual number of arguments passed to this function.
     776             :   TNode<IntPtrT> length = ChangeInt32ToIntPtr(
     777          56 :       UncheckedCast<Int32T>(Parameter(Descriptor::kJSActualArgumentsCount)));
     778             :   // 2. Let items be the List of arguments passed to this function.
     779             :   CodeStubArguments args(this, length, nullptr, INTPTR_PARAMETERS,
     780          56 :                          CodeStubArguments::ReceiverMode::kHasReceiver);
     781             : 
     782         112 :   Label if_not_constructor(this, Label::kDeferred),
     783         112 :       if_detached(this, Label::kDeferred);
     784             : 
     785             :   // 3. Let C be the this value.
     786             :   // 4. If IsConstructor(C) is false, throw a TypeError exception.
     787          56 :   TNode<Object> receiver = args.GetReceiver();
     788          56 :   GotoIf(TaggedIsSmi(receiver), &if_not_constructor);
     789          56 :   GotoIfNot(IsConstructor(CAST(receiver)), &if_not_constructor);
     790             : 
     791             :   // 5. Let newObj be ? TypedArrayCreate(C, len).
     792             :   TNode<JSTypedArray> new_typed_array = TypedArrayCreateByLength(
     793          56 :       context, receiver, SmiTag(length), "%TypedArray%.of");
     794             : 
     795          56 :   TNode<Word32T> elements_kind = LoadElementsKind(new_typed_array);
     796             : 
     797             :   // 6. Let k be 0.
     798             :   // 7. Repeat, while k < len
     799             :   //  a. Let kValue be items[k].
     800             :   //  b. Let Pk be ! ToString(k).
     801             :   //  c. Perform ? Set(newObj, Pk, kValue, true).
     802             :   //  d. Increase k by 1.
     803         112 :   DispatchTypedArrayByElementsKind(
     804             :       elements_kind,
     805         616 :       [&](ElementsKind kind, int size, int typed_array_fun_index) {
     806             :         TNode<FixedTypedArrayBase> elements =
     807        3080 :             CAST(LoadElements(new_typed_array));
     808        5544 :         BuildFastLoop(
     809        1848 :             IntPtrConstant(0), length,
     810         616 :             [&](Node* index) {
     811        1232 :               TNode<Object> item = args.AtIndex(index, INTPTR_PARAMETERS);
     812        3752 :               TNode<IntPtrT> intptr_index = UncheckedCast<IntPtrT>(index);
     813        1624 :               if (kind == BIGINT64_ELEMENTS || kind == BIGUINT64_ELEMENTS) {
     814        1232 :                 EmitBigTypedArrayElementStore(new_typed_array, elements,
     815        1232 :                                               intptr_index, item, context,
     816        1344 :                                               &if_detached);
     817             :               } else {
     818             :                 Node* value =
     819        1008 :                     PrepareValueForWriteToTypedArray(item, kind, context);
     820             : 
     821             :                 // ToNumber may execute JavaScript code, which could detach
     822             :                 // the array's buffer.
     823        1008 :                 Node* buffer = LoadObjectField(new_typed_array,
     824        2016 :                                                JSTypedArray::kBufferOffset);
     825        1008 :                 GotoIf(IsDetachedBuffer(buffer), &if_detached);
     826             : 
     827             :                 // GC may move backing store in ToNumber, thus load backing
     828             :                 // store everytime in this loop.
     829             :                 TNode<RawPtrT> backing_store =
     830         504 :                     LoadFixedTypedArrayBackingStore(elements);
     831        1008 :                 StoreElement(backing_store, kind, index, value,
     832         504 :                              INTPTR_PARAMETERS);
     833             :               }
     834         616 :             },
     835         616 :             1, ParameterMode::INTPTR_PARAMETERS, IndexAdvanceMode::kPost);
     836         672 :       });
     837             : 
     838             :   // 8. Return newObj.
     839          56 :   args.PopAndReturn(new_typed_array);
     840             : 
     841          56 :   BIND(&if_not_constructor);
     842          56 :   ThrowTypeError(context, MessageTemplate::kNotConstructor, receiver);
     843             : 
     844          56 :   BIND(&if_detached);
     845          56 :   ThrowTypeError(context, MessageTemplate::kDetachedOperation,
     846          56 :                  "%TypedArray%.of");
     847          56 : }
     848             : 
     849             : // ES6 #sec-%typedarray%.from
     850         336 : TF_BUILTIN(TypedArrayFrom, TypedArrayBuiltinsAssembler) {
     851          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
     852             : 
     853         112 :   Label check_iterator(this), from_array_like(this), fast_path(this),
     854         112 :       slow_path(this), create_typed_array(this), check_typedarray(this),
     855         112 :       if_not_constructor(this, Label::kDeferred),
     856         112 :       if_map_fn_not_callable(this, Label::kDeferred),
     857         112 :       if_iterator_fn_not_callable(this, Label::kDeferred),
     858         112 :       if_detached(this, Label::kDeferred);
     859             : 
     860             :   CodeStubArguments args(
     861             :       this,
     862          56 :       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount)));
     863          56 :   TNode<Object> source = args.GetOptionalArgumentValue(0);
     864             : 
     865             :   // 5. If thisArg is present, let T be thisArg; else let T be undefined.
     866          56 :   TNode<Object> this_arg = args.GetOptionalArgumentValue(2);
     867             : 
     868             :   // 1. Let C be the this value.
     869             :   // 2. If IsConstructor(C) is false, throw a TypeError exception.
     870          56 :   TNode<Object> receiver = args.GetReceiver();
     871          56 :   GotoIf(TaggedIsSmi(receiver), &if_not_constructor);
     872          56 :   GotoIfNot(IsConstructor(CAST(receiver)), &if_not_constructor);
     873             : 
     874             :   // 3. If mapfn is present and mapfn is not undefined, then
     875          56 :   TNode<Object> map_fn = args.GetOptionalArgumentValue(1);
     876         112 :   TVARIABLE(BoolT, mapping, Int32FalseConstant());
     877          56 :   GotoIf(IsUndefined(map_fn), &check_typedarray);
     878             : 
     879             :   //  a. If IsCallable(mapfn) is false, throw a TypeError exception.
     880             :   //  b. Let mapping be true.
     881             :   // 4. Else, let mapping be false.
     882          56 :   GotoIf(TaggedIsSmi(map_fn), &if_map_fn_not_callable);
     883          56 :   GotoIfNot(IsCallable(CAST(map_fn)), &if_map_fn_not_callable);
     884          56 :   mapping = Int32TrueConstant();
     885          56 :   Goto(&check_typedarray);
     886             : 
     887         112 :   TVARIABLE(Object, final_source);
     888         112 :   TVARIABLE(Smi, final_length);
     889             : 
     890             :   // We split up this builtin differently to the way it is written in the spec.
     891             :   // We already have great code in the elements accessor for copying from a
     892             :   // JSArray into a TypedArray, so we use that when possible. We only avoid
     893             :   // calling into the elements accessor when we have a mapping function, because
     894             :   // we can't handle that. Here, presence of a mapping function is the slow
     895             :   // path. We also combine the two different loops in the specification
     896             :   // (starting at 7.e and 13) because they are essentially identical. We also
     897             :   // save on code-size this way.
     898             : 
     899             :   // Get the iterator function
     900          56 :   BIND(&check_typedarray);
     901             :   TNode<Object> iterator_fn =
     902         112 :       CAST(GetMethod(context, source, isolate()->factory()->iterator_symbol(),
     903             :                      &from_array_like));
     904          56 :   GotoIf(TaggedIsSmi(iterator_fn), &if_iterator_fn_not_callable);
     905             : 
     906             :   {
     907             :     // TypedArrays have iterators, so normally we would go through the
     908             :     // IterableToList case below, which would convert the TypedArray to a
     909             :     // JSArray (boxing the values if they won't fit in a Smi).
     910             :     //
     911             :     // However, if we can guarantee that the source object has the built-in
     912             :     // iterator and that the %ArrayIteratorPrototype%.next method has not been
     913             :     // overridden, then we know the behavior of the iterator: returning the
     914             :     // values in the TypedArray sequentially from index 0 to length-1.
     915             :     //
     916             :     // In this case, we can avoid creating the intermediate array and the
     917             :     // associated HeapNumbers, and use the fast path in TypedArrayCopyElements
     918             :     // which uses the same ordering as the default iterator.
     919             :     //
     920             :     // Drop through to the default check_iterator behavior if any of these
     921             :     // checks fail.
     922             : 
     923             :     // Check that the source is a TypedArray
     924          56 :     GotoIf(TaggedIsSmi(source), &check_iterator);
     925          56 :     GotoIfNot(IsJSTypedArray(CAST(source)), &check_iterator);
     926             :     TNode<JSArrayBuffer> source_buffer =
     927          56 :         LoadJSArrayBufferViewBuffer(CAST(source));
     928          56 :     GotoIf(IsDetachedBuffer(source_buffer), &check_iterator);
     929             : 
     930             :     // Check that the iterator function is Builtins::kTypedArrayPrototypeValues
     931          56 :     GotoIfNot(IsJSFunction(CAST(iterator_fn)), &check_iterator);
     932             :     TNode<SharedFunctionInfo> shared_info = LoadObjectField<SharedFunctionInfo>(
     933          56 :         CAST(iterator_fn), JSFunction::kSharedFunctionInfoOffset);
     934         112 :     GotoIfNot(
     935         112 :         WordEqual(LoadObjectField(shared_info,
     936             :                                   SharedFunctionInfo::kFunctionDataOffset),
     937         112 :                   SmiConstant(Builtins::kTypedArrayPrototypeValues)),
     938          56 :         &check_iterator);
     939             :     // Check that the ArrayIterator prototype's "next" method hasn't been
     940             :     // overridden
     941             :     TNode<PropertyCell> protector_cell =
     942          56 :         CAST(LoadRoot(RootIndex::kArrayIteratorProtector));
     943         112 :     GotoIfNot(
     944         112 :         WordEqual(LoadObjectField(protector_cell, PropertyCell::kValueOffset),
     945         112 :                   SmiConstant(Isolate::kProtectorValid)),
     946          56 :         &check_iterator);
     947             : 
     948             :     // Source is a TypedArray with unmodified iterator behavior. Use the
     949             :     // source object directly, taking advantage of the special-case code in
     950             :     // TypedArrayCopyElements
     951          56 :     final_length = LoadJSTypedArrayLength(CAST(source));
     952          56 :     final_source = source;
     953          56 :     Goto(&create_typed_array);
     954             :   }
     955             : 
     956          56 :   BIND(&check_iterator);
     957             :   {
     958             :     // 6. Let usingIterator be ? GetMethod(source, @@iterator).
     959          56 :     GotoIfNot(IsCallable(CAST(iterator_fn)), &if_iterator_fn_not_callable);
     960             : 
     961             :     // We are using the iterator.
     962         112 :     Label if_length_not_smi(this, Label::kDeferred);
     963             :     // 7. If usingIterator is not undefined, then
     964             :     //  a. Let values be ? IterableToList(source, usingIterator).
     965             :     //  b. Let len be the number of elements in values.
     966          56 :     TNode<JSArray> values = CAST(
     967             :         CallBuiltin(Builtins::kIterableToList, context, source, iterator_fn));
     968             : 
     969             :     // This is not a spec'd limit, so it doesn't particularly matter when we
     970             :     // throw the range error for typed array length > MaxSmi.
     971          56 :     TNode<Object> raw_length = LoadJSArrayLength(values);
     972          56 :     GotoIfNot(TaggedIsSmi(raw_length), &if_length_not_smi);
     973             : 
     974          56 :     final_length = CAST(raw_length);
     975          56 :     final_source = values;
     976          56 :     Goto(&create_typed_array);
     977             : 
     978          56 :     BIND(&if_length_not_smi);
     979          56 :     ThrowRangeError(context, MessageTemplate::kInvalidTypedArrayLength,
     980          56 :                     raw_length);
     981             :   }
     982             : 
     983          56 :   BIND(&from_array_like);
     984             :   {
     985             :     // TODO(7881): support larger-than-smi typed array lengths
     986         112 :     Label if_length_not_smi(this, Label::kDeferred);
     987          56 :     final_source = source;
     988             : 
     989             :     // 10. Let len be ? ToLength(? Get(arrayLike, "length")).
     990             :     TNode<Object> raw_length =
     991          56 :         GetProperty(context, final_source.value(), LengthStringConstant());
     992          56 :     final_length = ToSmiLength(context, raw_length, &if_length_not_smi);
     993          56 :     Goto(&create_typed_array);
     994             : 
     995          56 :     BIND(&if_length_not_smi);
     996          56 :     ThrowRangeError(context, MessageTemplate::kInvalidTypedArrayLength,
     997          56 :                     raw_length);
     998             :   }
     999             : 
    1000         112 :   TVARIABLE(JSTypedArray, target_obj);
    1001             : 
    1002          56 :   BIND(&create_typed_array);
    1003             :   {
    1004             :     // 7c/11. Let targetObj be ? TypedArrayCreate(C, «len»).
    1005          56 :     target_obj = TypedArrayCreateByLength(
    1006          56 :         context, receiver, final_length.value(), "%TypedArray%.from");
    1007             : 
    1008          56 :     Branch(mapping.value(), &slow_path, &fast_path);
    1009             :   }
    1010             : 
    1011          56 :   BIND(&fast_path);
    1012             :   {
    1013         112 :     Label done(this);
    1014          56 :     GotoIf(SmiEqual(final_length.value(), SmiConstant(0)), &done);
    1015             : 
    1016             :     CallRuntime(Runtime::kTypedArrayCopyElements, context, target_obj.value(),
    1017          56 :                 final_source.value(), final_length.value());
    1018          56 :     Goto(&done);
    1019             : 
    1020          56 :     BIND(&done);
    1021          56 :     args.PopAndReturn(target_obj.value());
    1022             :   }
    1023             : 
    1024          56 :   BIND(&slow_path);
    1025          56 :   TNode<Word32T> elements_kind = LoadElementsKind(target_obj.value());
    1026             : 
    1027             :   // 7e/13 : Copy the elements
    1028          56 :   TNode<FixedTypedArrayBase> elements = CAST(LoadElements(target_obj.value()));
    1029         224 :   BuildFastLoop(
    1030         168 :       SmiConstant(0), final_length.value(),
    1031          56 :       [&](Node* index) {
    1032             :         TNode<Object> const k_value =
    1033         504 :             GetProperty(context, final_source.value(), index);
    1034             : 
    1035             :         TNode<Object> const mapped_value =
    1036         280 :             CAST(CallJS(CodeFactory::Call(isolate()), context, map_fn, this_arg,
    1037             :                         k_value, index));
    1038             : 
    1039         112 :         TNode<IntPtrT> intptr_index = SmiUntag(index);
    1040         392 :         DispatchTypedArrayByElementsKind(
    1041          56 :             elements_kind,
    1042         616 :             [&](ElementsKind kind, int size, int typed_array_fun_index) {
    1043         616 :               if (kind == BIGINT64_ELEMENTS || kind == BIGUINT64_ELEMENTS) {
    1044        1344 :                 EmitBigTypedArrayElementStore(target_obj.value(), elements,
    1045         616 :                                               intptr_index, mapped_value,
    1046        3416 :                                               context, &if_detached);
    1047             :               } else {
    1048        1008 :                 Node* const final_value = PrepareValueForWriteToTypedArray(
    1049         504 :                     mapped_value, kind, context);
    1050             : 
    1051             :                 // ToNumber may execute JavaScript code, which could detach
    1052             :                 // the array's buffer.
    1053        2016 :                 Node* buffer = LoadObjectField(target_obj.value(),
    1054        2016 :                                                JSTypedArray::kBufferOffset);
    1055        1008 :                 GotoIf(IsDetachedBuffer(buffer), &if_detached);
    1056             : 
    1057             :                 // GC may move backing store in map_fn, thus load backing
    1058             :                 // store in each iteration of this loop.
    1059             :                 TNode<RawPtrT> backing_store =
    1060         504 :                     LoadFixedTypedArrayBackingStore(elements);
    1061        1008 :                 StoreElement(backing_store, kind, index, final_value,
    1062         504 :                              SMI_PARAMETERS);
    1063             :               }
    1064         672 :             });
    1065          56 :       },
    1066          56 :       1, ParameterMode::SMI_PARAMETERS, IndexAdvanceMode::kPost);
    1067             : 
    1068          56 :   args.PopAndReturn(target_obj.value());
    1069             : 
    1070          56 :   BIND(&if_not_constructor);
    1071          56 :   ThrowTypeError(context, MessageTemplate::kNotConstructor, receiver);
    1072             : 
    1073          56 :   BIND(&if_map_fn_not_callable);
    1074          56 :   ThrowTypeError(context, MessageTemplate::kCalledNonCallable, map_fn);
    1075             : 
    1076          56 :   BIND(&if_iterator_fn_not_callable);
    1077          56 :   ThrowTypeError(context, MessageTemplate::kIteratorSymbolNonCallable);
    1078             : 
    1079          56 :   BIND(&if_detached);
    1080          56 :   ThrowTypeError(context, MessageTemplate::kDetachedOperation,
    1081          56 :                  "%TypedArray%.from");
    1082          56 : }
    1083             : 
    1084             : #undef V8_TYPED_ARRAY_MAX_SIZE_IN_HEAP
    1085             : 
    1086             : }  // namespace internal
    1087       87414 : }  // namespace v8

Generated by: LCOV version 1.10