LCOV - code coverage report
Current view: top level - src/builtins - builtins-typedarray-gen.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 283 298 95.0 %
Date: 2017-04-26 Functions: 29 30 96.7 %

          Line data    Source code
       1             : // Copyright 2017 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #include "src/builtins/builtins-utils-gen.h"
       6             : #include "src/builtins/builtins.h"
       7             : #include "src/code-stub-assembler.h"
       8             : 
       9             : namespace v8 {
      10             : namespace internal {
      11             : 
      12             : // -----------------------------------------------------------------------------
      13             : // ES6 section 22.2 TypedArray Objects
      14             : 
      15             : class TypedArrayBuiltinsAssembler : public CodeStubAssembler {
      16             :  public:
      17             :   explicit TypedArrayBuiltinsAssembler(compiler::CodeAssemblerState* state)
      18         473 :       : CodeStubAssembler(state) {}
      19             : 
      20             :  protected:
      21             :   void GenerateTypedArrayPrototypeGetter(Node* context, Node* receiver,
      22             :                                          const char* method_name,
      23             :                                          int object_offset);
      24             :   void GenerateTypedArrayPrototypeIterationMethod(Node* context, Node* receiver,
      25             :                                                   const char* method_name,
      26             :                                                   IterationKind iteration_kind);
      27             : 
      28             :   void SetupTypedArray(Node* holder, Node* length, Node* byte_offset,
      29             :                        Node* byte_length);
      30             :   void AttachBuffer(Node* holder, Node* buffer, Node* map, Node* length,
      31             :                     Node* byte_offset);
      32             : 
      33             :   Node* LoadMapForType(Node* array);
      34             :   Node* CalculateExternalPointer(Node* backing_store, Node* byte_offset);
      35             :   Node* LoadDataPtr(Node* typed_array);
      36             :   Node* ByteLengthIsValid(Node* byte_length);
      37             : };
      38             : 
      39          86 : compiler::Node* TypedArrayBuiltinsAssembler::LoadMapForType(Node* array) {
      40             :   CSA_ASSERT(this, IsJSTypedArray(array));
      41             : 
      42         172 :   Label unreachable(this), done(this);
      43          86 :   Label uint8_elements(this), uint8_clamped_elements(this), int8_elements(this),
      44          86 :       uint16_elements(this), int16_elements(this), uint32_elements(this),
      45          86 :       int32_elements(this), float32_elements(this), float64_elements(this);
      46             :   Label* elements_kind_labels[] = {
      47             :       &uint8_elements,  &uint8_clamped_elements, &int8_elements,
      48             :       &uint16_elements, &int16_elements,         &uint32_elements,
      49          86 :       &int32_elements,  &float32_elements,       &float64_elements};
      50             :   int32_t elements_kinds[] = {
      51             :       UINT8_ELEMENTS,  UINT8_CLAMPED_ELEMENTS, INT8_ELEMENTS,
      52             :       UINT16_ELEMENTS, INT16_ELEMENTS,         UINT32_ELEMENTS,
      53          86 :       INT32_ELEMENTS,  FLOAT32_ELEMENTS,       FLOAT64_ELEMENTS};
      54             :   const size_t kTypedElementsKindCount = LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND -
      55             :                                          FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND +
      56             :                                          1;
      57             :   DCHECK_EQ(kTypedElementsKindCount, arraysize(elements_kinds));
      58             :   DCHECK_EQ(kTypedElementsKindCount, arraysize(elements_kind_labels));
      59             : 
      60         172 :   VARIABLE(var_typed_map, MachineRepresentation::kTagged);
      61             : 
      62          86 :   Node* array_map = LoadMap(array);
      63          86 :   Node* elements_kind = LoadMapElementsKind(array_map);
      64             :   Switch(elements_kind, &unreachable, elements_kinds, elements_kind_labels,
      65          86 :          kTypedElementsKindCount);
      66             : 
      67         860 :   for (int i = 0; i < static_cast<int>(kTypedElementsKindCount); i++) {
      68         774 :     BIND(elements_kind_labels[i]);
      69             :     {
      70         774 :       ElementsKind kind = static_cast<ElementsKind>(elements_kinds[i]);
      71             :       ExternalArrayType type =
      72         774 :           isolate()->factory()->GetArrayTypeFromElementsKind(kind);
      73         774 :       Handle<Map> map(isolate()->heap()->MapForFixedTypedArray(type));
      74         774 :       var_typed_map.Bind(HeapConstant(map));
      75         774 :       Goto(&done);
      76             :     }
      77             :   }
      78             : 
      79          86 :   BIND(&unreachable);
      80          86 :   { Unreachable(); }
      81          86 :   BIND(&done);
      82         172 :   return var_typed_map.value();
      83             : }
      84             : 
      85             : // The byte_offset can be higher than Smi range, in which case to perform the
      86             : // pointer arithmetic necessary to calculate external_pointer, converting
      87             : // byte_offset to an intptr is more difficult. The max byte_offset is 8 * MaxSmi
      88             : // on the particular platform. 32 bit platforms are self-limiting, because we
      89             : // can't allocate an array bigger than our 32-bit arithmetic range anyway. 64
      90             : // bit platforms could theoretically have an offset up to 2^35 - 1, so we may
      91             : // need to convert the float heap number to an intptr.
      92          86 : compiler::Node* TypedArrayBuiltinsAssembler::CalculateExternalPointer(
      93             :     Node* backing_store, Node* byte_offset) {
      94          86 :   return IntPtrAdd(backing_store, ChangeNumberToIntPtr(byte_offset));
      95             : }
      96             : 
      97             : // Setup the TypedArray which is under construction.
      98             : //  - Set the length.
      99             : //  - Set the byte_offset.
     100             : //  - Set the byte_length.
     101             : //  - Set EmbedderFields to 0.
     102          86 : void TypedArrayBuiltinsAssembler::SetupTypedArray(Node* holder, Node* length,
     103             :                                                   Node* byte_offset,
     104             :                                                   Node* byte_length) {
     105             :   CSA_ASSERT(this, IsJSTypedArray(holder));
     106             :   CSA_ASSERT(this, TaggedIsSmi(length));
     107             :   CSA_ASSERT(this, IsNumber(byte_offset));
     108             :   CSA_ASSERT(this, IsNumber(byte_length));
     109             : 
     110          86 :   StoreObjectField(holder, JSTypedArray::kLengthOffset, length);
     111          86 :   StoreObjectField(holder, JSArrayBufferView::kByteOffsetOffset, byte_offset);
     112          86 :   StoreObjectField(holder, JSArrayBufferView::kByteLengthOffset, byte_length);
     113         258 :   for (int offset = JSTypedArray::kSize;
     114             :        offset < JSTypedArray::kSizeWithEmbedderFields; offset += kPointerSize) {
     115         172 :     StoreObjectField(holder, offset, SmiConstant(Smi::kZero));
     116             :   }
     117          86 : }
     118             : 
     119             : // Attach an off-heap buffer to a TypedArray.
     120          86 : void TypedArrayBuiltinsAssembler::AttachBuffer(Node* holder, Node* buffer,
     121             :                                                Node* map, Node* length,
     122             :                                                Node* byte_offset) {
     123             :   CSA_ASSERT(this, IsJSTypedArray(holder));
     124             :   CSA_ASSERT(this, IsJSArrayBuffer(buffer));
     125             :   CSA_ASSERT(this, IsMap(map));
     126             :   CSA_ASSERT(this, TaggedIsSmi(length));
     127             :   CSA_ASSERT(this, IsNumber(byte_offset));
     128             : 
     129          86 :   StoreObjectField(holder, JSArrayBufferView::kBufferOffset, buffer);
     130             : 
     131          86 :   Node* elements = Allocate(FixedTypedArrayBase::kHeaderSize);
     132          86 :   StoreMapNoWriteBarrier(elements, map);
     133          86 :   StoreObjectFieldNoWriteBarrier(elements, FixedArray::kLengthOffset, length);
     134             :   StoreObjectFieldNoWriteBarrier(
     135          86 :       elements, FixedTypedArrayBase::kBasePointerOffset, SmiConstant(0));
     136             : 
     137             :   Node* backing_store = LoadObjectField(
     138          86 :       buffer, JSArrayBuffer::kBackingStoreOffset, MachineType::Pointer());
     139             : 
     140          86 :   Node* external_pointer = CalculateExternalPointer(backing_store, byte_offset);
     141             :   StoreObjectFieldNoWriteBarrier(
     142             :       elements, FixedTypedArrayBase::kExternalPointerOffset, external_pointer,
     143          86 :       MachineType::PointerRepresentation());
     144             : 
     145          86 :   StoreObjectField(holder, JSObject::kElementsOffset, elements);
     146          86 : }
     147             : 
     148         172 : TF_BUILTIN(TypedArrayInitializeWithBuffer, TypedArrayBuiltinsAssembler) {
     149             :   Node* holder = Parameter(Descriptor::kHolder);
     150             :   Node* length = Parameter(Descriptor::kLength);
     151             :   Node* buffer = Parameter(Descriptor::kBuffer);
     152             :   Node* element_size = Parameter(Descriptor::kElementSize);
     153             :   Node* byte_offset = Parameter(Descriptor::kByteOffset);
     154             : 
     155             :   CSA_ASSERT(this, IsJSTypedArray(holder));
     156             :   CSA_ASSERT(this, TaggedIsSmi(length));
     157             :   CSA_ASSERT(this, IsJSArrayBuffer(buffer));
     158             :   CSA_ASSERT(this, TaggedIsSmi(element_size));
     159             :   CSA_ASSERT(this, IsNumber(byte_offset));
     160             : 
     161          43 :   Node* fixed_typed_map = LoadMapForType(holder);
     162             : 
     163             :   // SmiMul returns a heap number in case of Smi overflow.
     164          43 :   Node* byte_length = SmiMul(length, element_size);
     165             :   CSA_ASSERT(this, IsNumber(byte_length));
     166             : 
     167          43 :   SetupTypedArray(holder, length, byte_offset, byte_length);
     168          43 :   AttachBuffer(holder, buffer, fixed_typed_map, length, byte_offset);
     169          43 :   Return(UndefinedConstant());
     170          43 : }
     171             : 
     172         172 : TF_BUILTIN(TypedArrayInitialize, TypedArrayBuiltinsAssembler) {
     173             :   Node* holder = Parameter(Descriptor::kHolder);
     174             :   Node* length = Parameter(Descriptor::kLength);
     175             :   Node* element_size = Parameter(Descriptor::kElementSize);
     176             :   Node* initialize = Parameter(Descriptor::kInitialize);
     177             :   Node* context = Parameter(Descriptor::kContext);
     178             : 
     179             :   CSA_ASSERT(this, IsJSTypedArray(holder));
     180             :   CSA_ASSERT(this, TaggedIsPositiveSmi(length));
     181             :   CSA_ASSERT(this, TaggedIsPositiveSmi(element_size));
     182             :   CSA_ASSERT(this, IsBoolean(initialize));
     183             : 
     184          43 :   Node* byte_offset = SmiConstant(0);
     185             : 
     186             :   static const int32_t fta_base_data_offset =
     187             :       FixedTypedArrayBase::kDataOffset - kHeapObjectTag;
     188             : 
     189          43 :   Label setup_holder(this), allocate_on_heap(this), aligned(this),
     190          43 :       allocate_elements(this), allocate_off_heap(this),
     191          43 :       allocate_off_heap_no_init(this), attach_buffer(this), done(this);
     192          86 :   VARIABLE(var_total_size, MachineType::PointerRepresentation());
     193             : 
     194             :   // SmiMul returns a heap number in case of Smi overflow.
     195          43 :   Node* byte_length = SmiMul(length, element_size);
     196             :   CSA_ASSERT(this, IsNumber(byte_length));
     197             : 
     198          43 :   SetupTypedArray(holder, length, byte_offset, byte_length);
     199             : 
     200          43 :   Node* fixed_typed_map = LoadMapForType(holder);
     201          43 :   GotoIf(TaggedIsNotSmi(byte_length), &allocate_off_heap);
     202             :   GotoIf(SmiGreaterThan(byte_length,
     203             :                         SmiConstant(FLAG_typed_array_max_size_in_heap)),
     204          43 :          &allocate_off_heap);
     205          43 :   Goto(&allocate_on_heap);
     206             : 
     207          43 :   BIND(&allocate_on_heap);
     208             :   {
     209             :     CSA_ASSERT(this, TaggedIsPositiveSmi(byte_length));
     210             :     // Allocate a new ArrayBuffer and initialize it with empty properties and
     211             :     // elements.
     212          43 :     Node* native_context = LoadNativeContext(context);
     213             :     Node* map =
     214          43 :         LoadContextElement(native_context, Context::ARRAY_BUFFER_MAP_INDEX);
     215          43 :     Node* empty_fixed_array = LoadRoot(Heap::kEmptyFixedArrayRootIndex);
     216             : 
     217          43 :     Node* buffer = Allocate(JSArrayBuffer::kSizeWithEmbedderFields);
     218          43 :     StoreMapNoWriteBarrier(buffer, map);
     219             :     StoreObjectFieldNoWriteBarrier(buffer, JSArray::kPropertiesOffset,
     220          43 :                                    empty_fixed_array);
     221             :     StoreObjectFieldNoWriteBarrier(buffer, JSArray::kElementsOffset,
     222          43 :                                    empty_fixed_array);
     223             :     // Setup the ArrayBuffer.
     224             :     //  - Set BitField to 0.
     225             :     //  - Set IsExternal and IsNeuterable bits of BitFieldSlot.
     226             :     //  - Set the byte_length field to byte_length.
     227             :     //  - Set backing_store to null/Smi(0).
     228             :     //  - Set all embedder fields to Smi(0).
     229             :     StoreObjectFieldNoWriteBarrier(buffer, JSArrayBuffer::kBitFieldSlot,
     230          43 :                                    SmiConstant(Smi::kZero));
     231             :     int32_t bitfield_value = (1 << JSArrayBuffer::IsExternal::kShift) |
     232             :                              (1 << JSArrayBuffer::IsNeuterable::kShift);
     233             :     StoreObjectFieldNoWriteBarrier(buffer, JSArrayBuffer::kBitFieldOffset,
     234             :                                    Int32Constant(bitfield_value),
     235          43 :                                    MachineRepresentation::kWord32);
     236             : 
     237             :     StoreObjectFieldNoWriteBarrier(buffer, JSArrayBuffer::kByteLengthOffset,
     238          43 :                                    byte_length);
     239             :     StoreObjectFieldNoWriteBarrier(buffer, JSArrayBuffer::kBackingStoreOffset,
     240          43 :                                    SmiConstant(Smi::kZero));
     241         129 :     for (int i = 0; i < v8::ArrayBuffer::kEmbedderFieldCount; i++) {
     242          86 :       int offset = JSArrayBuffer::kSize + i * kPointerSize;
     243          86 :       StoreObjectFieldNoWriteBarrier(buffer, offset, SmiConstant(Smi::kZero));
     244             :     }
     245             : 
     246          43 :     StoreObjectField(holder, JSArrayBufferView::kBufferOffset, buffer);
     247             : 
     248             :     // Check the alignment.
     249             :     GotoIf(SmiEqual(SmiMod(element_size, SmiConstant(kObjectAlignment)),
     250             :                     SmiConstant(0)),
     251          43 :            &aligned);
     252             : 
     253             :     // Fix alignment if needed.
     254             :     DCHECK_EQ(0, FixedTypedArrayBase::kHeaderSize & kObjectAlignmentMask);
     255             :     Node* aligned_header_size =
     256          43 :         IntPtrConstant(FixedTypedArrayBase::kHeaderSize + kObjectAlignmentMask);
     257          43 :     Node* size = IntPtrAdd(SmiToWord(byte_length), aligned_header_size);
     258          43 :     var_total_size.Bind(WordAnd(size, IntPtrConstant(~kObjectAlignmentMask)));
     259          43 :     Goto(&allocate_elements);
     260             :   }
     261             : 
     262          43 :   BIND(&aligned);
     263             :   {
     264          43 :     Node* header_size = IntPtrConstant(FixedTypedArrayBase::kHeaderSize);
     265          43 :     var_total_size.Bind(IntPtrAdd(SmiToWord(byte_length), header_size));
     266          43 :     Goto(&allocate_elements);
     267             :   }
     268             : 
     269          43 :   BIND(&allocate_elements);
     270             :   {
     271             :     // Allocate a FixedTypedArray and set the length, base pointer and external
     272             :     // pointer.
     273             :     CSA_ASSERT(this, IsRegularHeapObjectSize(var_total_size.value()));
     274             : 
     275             :     Node* elements;
     276             :     int heap_alignment =
     277          43 :         ElementSizeLog2Of(MachineType::PointerRepresentation());
     278             : 
     279         129 :     if (UnalignedLoadSupported(MachineType::Float64(), heap_alignment) &&
     280          86 :         UnalignedStoreSupported(MachineType::Float64(), heap_alignment)) {
     281          43 :       elements = AllocateInNewSpace(var_total_size.value());
     282             :     } else {
     283           0 :       elements = AllocateInNewSpace(var_total_size.value(), kDoubleAlignment);
     284             :     }
     285             : 
     286          43 :     StoreMapNoWriteBarrier(elements, fixed_typed_map);
     287          43 :     StoreObjectFieldNoWriteBarrier(elements, FixedArray::kLengthOffset, length);
     288             :     StoreObjectFieldNoWriteBarrier(
     289          43 :         elements, FixedTypedArrayBase::kBasePointerOffset, elements);
     290             :     StoreObjectFieldNoWriteBarrier(elements,
     291             :                                    FixedTypedArrayBase::kExternalPointerOffset,
     292             :                                    IntPtrConstant(fta_base_data_offset),
     293          43 :                                    MachineType::PointerRepresentation());
     294             : 
     295          43 :     StoreObjectField(holder, JSObject::kElementsOffset, elements);
     296             : 
     297          43 :     GotoIf(IsFalse(initialize), &done);
     298             :     // Initialize the backing store by filling it with 0s.
     299             :     Node* backing_store = IntPtrAdd(BitcastTaggedToWord(elements),
     300          43 :                                     IntPtrConstant(fta_base_data_offset));
     301             :     // Call out to memset to perform initialization.
     302             :     Node* memset =
     303          43 :         ExternalConstant(ExternalReference::libc_memset_function(isolate()));
     304             :     CallCFunction3(MachineType::AnyTagged(), MachineType::Pointer(),
     305             :                    MachineType::IntPtr(), MachineType::UintPtr(), memset,
     306          43 :                    backing_store, IntPtrConstant(0), SmiToWord(byte_length));
     307          43 :     Goto(&done);
     308             :   }
     309             : 
     310          86 :   VARIABLE(var_buffer, MachineRepresentation::kTagged);
     311             : 
     312          43 :   BIND(&allocate_off_heap);
     313             :   {
     314          43 :     GotoIf(IsFalse(initialize), &allocate_off_heap_no_init);
     315             : 
     316             :     Node* buffer_constructor = LoadContextElement(
     317          43 :         LoadNativeContext(context), Context::ARRAY_BUFFER_FUN_INDEX);
     318             :     var_buffer.Bind(ConstructJS(CodeFactory::Construct(isolate()), context,
     319          86 :                                 buffer_constructor, byte_length));
     320          43 :     Goto(&attach_buffer);
     321             :   }
     322             : 
     323          43 :   BIND(&allocate_off_heap_no_init);
     324             :   {
     325             :     Node* buffer_constructor_noinit = LoadContextElement(
     326          43 :         LoadNativeContext(context), Context::ARRAY_BUFFER_NOINIT_FUN_INDEX);
     327             :     var_buffer.Bind(CallJS(CodeFactory::Call(isolate()), context,
     328             :                            buffer_constructor_noinit, UndefinedConstant(),
     329          86 :                            byte_length));
     330          43 :     Goto(&attach_buffer);
     331             :   }
     332             : 
     333          43 :   BIND(&attach_buffer);
     334             :   {
     335             :     AttachBuffer(holder, var_buffer.value(), fixed_typed_map, length,
     336          43 :                  byte_offset);
     337          43 :     Goto(&done);
     338             :   }
     339             : 
     340          43 :   BIND(&done);
     341          86 :   Return(UndefinedConstant());
     342          43 : }
     343             : 
     344             : // ES6 #sec-typedarray-length
     345         172 : TF_BUILTIN(TypedArrayConstructByLength, TypedArrayBuiltinsAssembler) {
     346             :   Node* holder = Parameter(Descriptor::kHolder);
     347             :   Node* length = Parameter(Descriptor::kLength);
     348             :   Node* element_size = Parameter(Descriptor::kElementSize);
     349             :   Node* context = Parameter(Descriptor::kContext);
     350             : 
     351             :   CSA_ASSERT(this, IsJSTypedArray(holder));
     352             :   CSA_ASSERT(this, TaggedIsPositiveSmi(element_size));
     353             : 
     354          43 :   Node* initialize = BooleanConstant(true);
     355             : 
     356             :   Label invalid_length(this);
     357             : 
     358          43 :   length = ToInteger(context, length, CodeStubAssembler::kTruncateMinusZero);
     359             :   // The maximum length of a TypedArray is MaxSmi().
     360             :   // Note: this is not per spec, but rather a constraint of our current
     361             :   // representation (which uses smi's).
     362          43 :   GotoIf(TaggedIsNotSmi(length), &invalid_length);
     363          43 :   GotoIf(SmiLessThan(length, SmiConstant(0)), &invalid_length);
     364             : 
     365             :   CallBuiltin(Builtins::kTypedArrayInitialize, context, holder, length,
     366          43 :               element_size, initialize);
     367          43 :   Return(UndefinedConstant());
     368             : 
     369          43 :   BIND(&invalid_length);
     370             :   {
     371             :     CallRuntime(Runtime::kThrowRangeError, context,
     372          43 :                 SmiConstant(MessageTemplate::kInvalidTypedArrayLength), length);
     373          43 :     Unreachable();
     374          43 :   }
     375          43 : }
     376             : 
     377             : // ES6 #sec-typedarray-buffer-byteoffset-length
     378         172 : TF_BUILTIN(TypedArrayConstructByArrayBuffer, TypedArrayBuiltinsAssembler) {
     379             :   Node* holder = Parameter(Descriptor::kHolder);
     380             :   Node* buffer = Parameter(Descriptor::kBuffer);
     381             :   Node* byte_offset = Parameter(Descriptor::kByteOffset);
     382             :   Node* length = Parameter(Descriptor::kLength);
     383             :   Node* element_size = Parameter(Descriptor::kElementSize);
     384             :   Node* context = Parameter(Descriptor::kContext);
     385             : 
     386             :   CSA_ASSERT(this, IsJSTypedArray(holder));
     387             :   CSA_ASSERT(this, IsJSArrayBuffer(buffer));
     388             :   CSA_ASSERT(this, TaggedIsPositiveSmi(element_size));
     389             : 
     390          43 :   VARIABLE(new_byte_length, MachineRepresentation::kTagged, SmiConstant(0));
     391          86 :   VARIABLE(offset, MachineRepresentation::kTagged, SmiConstant(0));
     392             : 
     393          43 :   Label start_offset_error(this, Label::kDeferred),
     394          43 :       byte_length_error(this, Label::kDeferred),
     395          43 :       invalid_offset_error(this, Label::kDeferred);
     396          43 :   Label offset_is_smi(this), offset_not_smi(this, Label::kDeferred),
     397          43 :       check_length(this), call_init(this), invalid_length(this),
     398          43 :       length_undefined(this), length_defined(this);
     399             : 
     400          43 :   Callable add = CodeFactory::Add(isolate());
     401          43 :   Callable div = CodeFactory::Divide(isolate());
     402          43 :   Callable equal = CodeFactory::Equal(isolate());
     403          43 :   Callable greater_than = CodeFactory::GreaterThan(isolate());
     404          43 :   Callable less_than = CodeFactory::LessThan(isolate());
     405          43 :   Callable mod = CodeFactory::Modulus(isolate());
     406          43 :   Callable sub = CodeFactory::Subtract(isolate());
     407             : 
     408          43 :   GotoIf(IsUndefined(byte_offset), &check_length);
     409             : 
     410             :   offset.Bind(
     411          43 :       ToInteger(context, byte_offset, CodeStubAssembler::kTruncateMinusZero));
     412          43 :   Branch(TaggedIsSmi(offset.value()), &offset_is_smi, &offset_not_smi);
     413             : 
     414             :   // Check that the offset is a multiple of the element size.
     415          43 :   BIND(&offset_is_smi);
     416             :   {
     417          43 :     GotoIf(SmiEqual(offset.value(), SmiConstant(0)), &check_length);
     418          43 :     GotoIf(SmiLessThan(offset.value(), SmiConstant(0)), &invalid_length);
     419          43 :     Node* remainder = SmiMod(offset.value(), element_size);
     420             :     Branch(SmiEqual(remainder, SmiConstant(0)), &check_length,
     421          43 :            &start_offset_error);
     422             :   }
     423          43 :   BIND(&offset_not_smi);
     424             :   {
     425             :     GotoIf(IsTrue(CallStub(less_than, context, offset.value(), SmiConstant(0))),
     426          43 :            &invalid_length);
     427          43 :     Node* remainder = CallStub(mod, context, offset.value(), element_size);
     428             :     // Remainder can be a heap number.
     429             :     Branch(IsTrue(CallStub(equal, context, remainder, SmiConstant(0))),
     430          43 :            &check_length, &start_offset_error);
     431             :   }
     432             : 
     433          43 :   BIND(&check_length);
     434             :   // TODO(petermarshall): Throw on detached typedArray.
     435          43 :   Branch(IsUndefined(length), &length_undefined, &length_defined);
     436             : 
     437          43 :   BIND(&length_undefined);
     438             :   {
     439             :     Node* buffer_byte_length =
     440          43 :         LoadObjectField(buffer, JSArrayBuffer::kByteLengthOffset);
     441             : 
     442          43 :     Node* remainder = CallStub(mod, context, buffer_byte_length, element_size);
     443             :     // Remainder can be a heap number.
     444             :     GotoIf(IsFalse(CallStub(equal, context, remainder, SmiConstant(0))),
     445          43 :            &byte_length_error);
     446             : 
     447             :     new_byte_length.Bind(
     448          43 :         CallStub(sub, context, buffer_byte_length, offset.value()));
     449             : 
     450             :     Branch(IsTrue(CallStub(less_than, context, new_byte_length.value(),
     451             :                            SmiConstant(0))),
     452          43 :            &invalid_offset_error, &call_init);
     453             :   }
     454             : 
     455          43 :   BIND(&length_defined);
     456             :   {
     457          43 :     Node* new_length = ToSmiIndex(length, context, &invalid_length);
     458          43 :     new_byte_length.Bind(SmiMul(new_length, element_size));
     459             :     // Reading the byte length must come after the ToIndex operation, which
     460             :     // could cause the buffer to become detached.
     461             :     Node* buffer_byte_length =
     462          43 :         LoadObjectField(buffer, JSArrayBuffer::kByteLengthOffset);
     463             : 
     464          43 :     Node* end = CallStub(add, context, offset.value(), new_byte_length.value());
     465             : 
     466             :     Branch(IsTrue(CallStub(greater_than, context, end, buffer_byte_length)),
     467          43 :            &invalid_length, &call_init);
     468             :   }
     469             : 
     470          43 :   BIND(&call_init);
     471             :   {
     472             :     Node* new_length =
     473          43 :         CallStub(div, context, new_byte_length.value(), element_size);
     474             :     // Force the result into a Smi, or throw a range error if it doesn't fit.
     475          43 :     new_length = ToSmiIndex(new_length, context, &invalid_length);
     476             : 
     477             :     CallBuiltin(Builtins::kTypedArrayInitializeWithBuffer, context, holder,
     478          43 :                 new_length, buffer, element_size, offset.value());
     479          43 :     Return(UndefinedConstant());
     480             :   }
     481             : 
     482          43 :   BIND(&invalid_offset_error);
     483             :   {
     484             :     CallRuntime(Runtime::kThrowRangeError, context,
     485          43 :                 SmiConstant(MessageTemplate::kInvalidOffset), byte_offset);
     486          43 :     Unreachable();
     487             :   }
     488             : 
     489          43 :   BIND(&start_offset_error);
     490             :   {
     491          43 :     Node* holder_map = LoadMap(holder);
     492             :     Node* problem_string = HeapConstant(
     493          86 :         factory()->NewStringFromAsciiChecked("start offset", TENURED));
     494             :     CallRuntime(Runtime::kThrowInvalidTypedArrayAlignment, context, holder_map,
     495          43 :                 problem_string);
     496             : 
     497          43 :     Unreachable();
     498             :   }
     499             : 
     500          43 :   BIND(&byte_length_error);
     501             :   {
     502          43 :     Node* holder_map = LoadMap(holder);
     503             :     Node* problem_string = HeapConstant(
     504          86 :         factory()->NewStringFromAsciiChecked("byte length", TENURED));
     505             :     CallRuntime(Runtime::kThrowInvalidTypedArrayAlignment, context, holder_map,
     506          43 :                 problem_string);
     507             : 
     508          43 :     Unreachable();
     509             :   }
     510             : 
     511          43 :   BIND(&invalid_length);
     512             :   {
     513             :     CallRuntime(Runtime::kThrowRangeError, context,
     514          43 :                 SmiConstant(MessageTemplate::kInvalidTypedArrayLength), length);
     515          43 :     Unreachable();
     516          43 :   }
     517          43 : }
     518             : 
     519          86 : compiler::Node* TypedArrayBuiltinsAssembler::LoadDataPtr(Node* typed_array) {
     520             :   CSA_ASSERT(this, IsJSTypedArray(typed_array));
     521          86 :   Node* elements = LoadElements(typed_array);
     522             :   CSA_ASSERT(this, IsFixedTypedArray(elements));
     523             :   Node* base_pointer = BitcastTaggedToWord(
     524          86 :       LoadObjectField(elements, FixedTypedArrayBase::kBasePointerOffset));
     525             :   Node* external_pointer = BitcastTaggedToWord(
     526          86 :       LoadObjectField(elements, FixedTypedArrayBase::kExternalPointerOffset));
     527          86 :   return IntPtrAdd(base_pointer, external_pointer);
     528             : }
     529             : 
     530           0 : compiler::Node* TypedArrayBuiltinsAssembler::ByteLengthIsValid(
     531             :     Node* byte_length) {
     532           0 :   Label smi(this), done(this);
     533           0 :   VARIABLE(is_valid, MachineRepresentation::kWord32);
     534           0 :   GotoIf(TaggedIsSmi(byte_length), &smi);
     535             : 
     536             :   CSA_ASSERT(this, IsHeapNumber(byte_length));
     537           0 :   Node* float_value = LoadHeapNumberValue(byte_length);
     538             :   Node* max_byte_length_double =
     539           0 :       Float64Constant(FixedTypedArrayBase::kMaxByteLength);
     540           0 :   is_valid.Bind(Float64LessThanOrEqual(float_value, max_byte_length_double));
     541           0 :   Goto(&done);
     542             : 
     543           0 :   BIND(&smi);
     544           0 :   Node* max_byte_length = IntPtrConstant(FixedTypedArrayBase::kMaxByteLength);
     545           0 :   is_valid.Bind(UintPtrLessThanOrEqual(SmiUntag(byte_length), max_byte_length));
     546           0 :   Goto(&done);
     547             : 
     548           0 :   BIND(&done);
     549           0 :   return is_valid.value();
     550             : }
     551             : 
     552         172 : TF_BUILTIN(TypedArrayConstructByArrayLike, TypedArrayBuiltinsAssembler) {
     553             :   Node* holder = Parameter(Descriptor::kHolder);
     554             :   Node* array_like = Parameter(Descriptor::kArrayLike);
     555             :   Node* initial_length = Parameter(Descriptor::kLength);
     556             :   Node* element_size = Parameter(Descriptor::kElementSize);
     557             :   CSA_ASSERT(this, TaggedIsSmi(element_size));
     558             :   Node* context = Parameter(Descriptor::kContext);
     559             : 
     560          43 :   Node* initialize = BooleanConstant(false);
     561             : 
     562          43 :   Label invalid_length(this), fill(this), fast_copy(this);
     563             : 
     564             :   // The caller has looked up length on array_like, which is observable.
     565          43 :   Node* length = ToSmiLength(initial_length, context, &invalid_length);
     566             : 
     567             :   CallBuiltin(Builtins::kTypedArrayInitialize, context, holder, length,
     568          43 :               element_size, initialize);
     569          43 :   GotoIf(SmiNotEqual(length, SmiConstant(0)), &fill);
     570          43 :   Return(UndefinedConstant());
     571             : 
     572          43 :   BIND(&fill);
     573          43 :   Node* holder_kind = LoadMapElementsKind(LoadMap(holder));
     574          43 :   Node* source_kind = LoadMapElementsKind(LoadMap(array_like));
     575          43 :   GotoIf(Word32Equal(holder_kind, source_kind), &fast_copy);
     576             : 
     577             :   // Copy using the elements accessor.
     578             :   CallRuntime(Runtime::kTypedArrayCopyElements, context, holder, array_like,
     579          43 :               length);
     580          43 :   Return(UndefinedConstant());
     581             : 
     582          43 :   BIND(&fast_copy);
     583             :   {
     584          43 :     Node* holder_data_ptr = LoadDataPtr(holder);
     585          43 :     Node* source_data_ptr = LoadDataPtr(array_like);
     586             : 
     587             :     // Calculate the byte length. We shouldn't be trying to copy if the typed
     588             :     // array was neutered.
     589             :     CSA_ASSERT(this, SmiNotEqual(length, SmiConstant(0)));
     590             :     CSA_ASSERT(this, Word32Equal(IsDetachedBuffer(LoadObjectField(
     591             :                                      array_like, JSTypedArray::kBufferOffset)),
     592             :                                  Int32Constant(0)));
     593             : 
     594          43 :     Node* byte_length = SmiMul(length, element_size);
     595             :     CSA_ASSERT(this, ByteLengthIsValid(byte_length));
     596          43 :     Node* byte_length_intptr = ChangeNumberToIntPtr(byte_length);
     597             :     CSA_ASSERT(this, UintPtrLessThanOrEqual(
     598             :                          byte_length_intptr,
     599             :                          IntPtrConstant(FixedTypedArrayBase::kMaxByteLength)));
     600             : 
     601             :     Node* memcpy =
     602          43 :         ExternalConstant(ExternalReference::libc_memcpy_function(isolate()));
     603             :     CallCFunction3(MachineType::AnyTagged(), MachineType::Pointer(),
     604             :                    MachineType::Pointer(), MachineType::UintPtr(), memcpy,
     605          43 :                    holder_data_ptr, source_data_ptr, byte_length_intptr);
     606          43 :     Return(UndefinedConstant());
     607             :   }
     608             : 
     609          43 :   BIND(&invalid_length);
     610             :   {
     611             :     CallRuntime(Runtime::kThrowRangeError, context,
     612             :                 SmiConstant(MessageTemplate::kInvalidTypedArrayLength),
     613          43 :                 initial_length);
     614          43 :     Unreachable();
     615          43 :   }
     616          43 : }
     617             : 
     618         129 : void TypedArrayBuiltinsAssembler::GenerateTypedArrayPrototypeGetter(
     619             :     Node* context, Node* receiver, const char* method_name, int object_offset) {
     620             :   // Check if the {receiver} is actually a JSTypedArray.
     621         129 :   Label receiver_is_incompatible(this, Label::kDeferred);
     622         129 :   GotoIf(TaggedIsSmi(receiver), &receiver_is_incompatible);
     623             :   GotoIfNot(HasInstanceType(receiver, JS_TYPED_ARRAY_TYPE),
     624         129 :             &receiver_is_incompatible);
     625             : 
     626             :   // Check if the {receiver}'s JSArrayBuffer was neutered.
     627             :   Node* receiver_buffer =
     628         129 :       LoadObjectField(receiver, JSTypedArray::kBufferOffset);
     629         129 :   Label if_receiverisneutered(this, Label::kDeferred);
     630         129 :   GotoIf(IsDetachedBuffer(receiver_buffer), &if_receiverisneutered);
     631         129 :   Return(LoadObjectField(receiver, object_offset));
     632             : 
     633         129 :   BIND(&if_receiverisneutered);
     634             :   {
     635             :     // The {receiver}s buffer was neutered, default to zero.
     636         129 :     Return(SmiConstant(0));
     637             :   }
     638             : 
     639         129 :   BIND(&receiver_is_incompatible);
     640             :   {
     641             :     // The {receiver} is not a valid JSTypedArray.
     642             :     CallRuntime(Runtime::kThrowIncompatibleMethodReceiver, context,
     643             :                 HeapConstant(
     644             :                     factory()->NewStringFromAsciiChecked(method_name, TENURED)),
     645         258 :                 receiver);
     646         129 :     Unreachable();
     647         129 :   }
     648         129 : }
     649             : 
     650             : // ES6 #sec-get-%typedarray%.prototype.bytelength
     651         172 : TF_BUILTIN(TypedArrayPrototypeByteLength, TypedArrayBuiltinsAssembler) {
     652             :   Node* context = Parameter(Descriptor::kContext);
     653             :   Node* receiver = Parameter(Descriptor::kReceiver);
     654             :   GenerateTypedArrayPrototypeGetter(context, receiver,
     655             :                                     "get TypedArray.prototype.byteLength",
     656          43 :                                     JSTypedArray::kByteLengthOffset);
     657          43 : }
     658             : 
     659             : // ES6 #sec-get-%typedarray%.prototype.byteoffset
     660         172 : TF_BUILTIN(TypedArrayPrototypeByteOffset, TypedArrayBuiltinsAssembler) {
     661             :   Node* context = Parameter(Descriptor::kContext);
     662             :   Node* receiver = Parameter(Descriptor::kReceiver);
     663             :   GenerateTypedArrayPrototypeGetter(context, receiver,
     664             :                                     "get TypedArray.prototype.byteOffset",
     665          43 :                                     JSTypedArray::kByteOffsetOffset);
     666          43 : }
     667             : 
     668             : // ES6 #sec-get-%typedarray%.prototype.length
     669         172 : TF_BUILTIN(TypedArrayPrototypeLength, TypedArrayBuiltinsAssembler) {
     670             :   Node* context = Parameter(Descriptor::kContext);
     671             :   Node* receiver = Parameter(Descriptor::kReceiver);
     672             :   GenerateTypedArrayPrototypeGetter(context, receiver,
     673             :                                     "get TypedArray.prototype.length",
     674          43 :                                     JSTypedArray::kLengthOffset);
     675          43 : }
     676             : 
     677         129 : void TypedArrayBuiltinsAssembler::GenerateTypedArrayPrototypeIterationMethod(
     678             :     Node* context, Node* receiver, const char* method_name,
     679             :     IterationKind iteration_kind) {
     680         129 :   Label throw_bad_receiver(this, Label::kDeferred);
     681         129 :   Label throw_typeerror(this, Label::kDeferred);
     682             : 
     683         129 :   GotoIf(TaggedIsSmi(receiver), &throw_bad_receiver);
     684             : 
     685         129 :   Node* map = LoadMap(receiver);
     686         129 :   Node* instance_type = LoadMapInstanceType(map);
     687             :   GotoIf(Word32NotEqual(instance_type, Int32Constant(JS_TYPED_ARRAY_TYPE)),
     688         129 :          &throw_bad_receiver);
     689             : 
     690             :   // Check if the {receiver}'s JSArrayBuffer was neutered.
     691             :   Node* receiver_buffer =
     692         129 :       LoadObjectField(receiver, JSTypedArray::kBufferOffset);
     693         129 :   Label if_receiverisneutered(this, Label::kDeferred);
     694         129 :   GotoIf(IsDetachedBuffer(receiver_buffer), &if_receiverisneutered);
     695             : 
     696             :   Return(CreateArrayIterator(receiver, map, instance_type, context,
     697         129 :                              iteration_kind));
     698             : 
     699         258 :   VARIABLE(var_message, MachineRepresentation::kTagged);
     700         129 :   BIND(&throw_bad_receiver);
     701         129 :   var_message.Bind(SmiConstant(MessageTemplate::kNotTypedArray));
     702         129 :   Goto(&throw_typeerror);
     703             : 
     704         129 :   BIND(&if_receiverisneutered);
     705             :   var_message.Bind(
     706         129 :       SmiConstant(Smi::FromInt(MessageTemplate::kDetachedOperation)));
     707         129 :   Goto(&throw_typeerror);
     708             : 
     709         129 :   BIND(&throw_typeerror);
     710             :   {
     711             :     Node* method_arg = HeapConstant(
     712         258 :         isolate()->factory()->NewStringFromAsciiChecked(method_name, TENURED));
     713             :     Node* result = CallRuntime(Runtime::kThrowTypeError, context,
     714         129 :                                var_message.value(), method_arg);
     715         129 :     Return(result);
     716         129 :   }
     717         129 : }
     718             : 
     719             : // ES6 #sec-%typedarray%.prototype.values
     720         172 : TF_BUILTIN(TypedArrayPrototypeValues, TypedArrayBuiltinsAssembler) {
     721             :   Node* context = Parameter(Descriptor::kContext);
     722             :   Node* receiver = Parameter(Descriptor::kReceiver);
     723             :   GenerateTypedArrayPrototypeIterationMethod(context, receiver,
     724             :                                              "%TypedArray%.prototype.values()",
     725          43 :                                              IterationKind::kValues);
     726          43 : }
     727             : 
     728             : // ES6 #sec-%typedarray%.prototype.entries
     729         172 : TF_BUILTIN(TypedArrayPrototypeEntries, TypedArrayBuiltinsAssembler) {
     730             :   Node* context = Parameter(Descriptor::kContext);
     731             :   Node* receiver = Parameter(Descriptor::kReceiver);
     732             :   GenerateTypedArrayPrototypeIterationMethod(context, receiver,
     733             :                                              "%TypedArray%.prototype.entries()",
     734          43 :                                              IterationKind::kEntries);
     735          43 : }
     736             : 
     737             : // ES6 #sec-%typedarray%.prototype.keys
     738         172 : TF_BUILTIN(TypedArrayPrototypeKeys, TypedArrayBuiltinsAssembler) {
     739             :   Node* context = Parameter(Descriptor::kContext);
     740             :   Node* receiver = Parameter(Descriptor::kReceiver);
     741             :   GenerateTypedArrayPrototypeIterationMethod(
     742          43 :       context, receiver, "%TypedArray%.prototype.keys()", IterationKind::kKeys);
     743          43 : }
     744             : 
     745             : }  // namespace internal
     746             : }  // namespace v8

Generated by: LCOV version 1.10