• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/execution/protectors.h"
12 #include "src/handles/handles-inl.h"
13 #include "src/heap/factory-inl.h"
14 #include "src/objects/js-array-buffer-inl.h"
15 
16 namespace v8 {
17 namespace internal {
18 
19 // -----------------------------------------------------------------------------
20 // ES6 section 22.2 TypedArray Objects
21 
22 // Sets the embedder fields to 0 for a TypedArray which is under construction.
SetupTypedArrayEmbedderFields(TNode<JSTypedArray> holder)23 void TypedArrayBuiltinsAssembler::SetupTypedArrayEmbedderFields(
24     TNode<JSTypedArray> holder) {
25   for (int offset = JSTypedArray::kHeaderSize;
26        offset < JSTypedArray::kSizeWithEmbedderFields; offset += kTaggedSize) {
27     // TODO(v8:10391, saelo): Handle external pointers in EmbedderDataSlot
28     StoreObjectField(holder, offset, SmiConstant(0));
29   }
30 }
31 
32 // Allocate a new ArrayBuffer and initialize it with empty properties and
33 // elements.
34 // TODO(bmeurer,v8:4153): Rename this and maybe fix up the implementation a bit.
AllocateEmptyOnHeapBuffer(TNode<Context> context)35 TNode<JSArrayBuffer> TypedArrayBuiltinsAssembler::AllocateEmptyOnHeapBuffer(
36     TNode<Context> context) {
37   TNode<NativeContext> native_context = LoadNativeContext(context);
38   TNode<Map> map =
39       CAST(LoadContextElement(native_context, Context::ARRAY_BUFFER_MAP_INDEX));
40   TNode<FixedArray> empty_fixed_array = EmptyFixedArrayConstant();
41 
42   TNode<JSArrayBuffer> buffer = UncheckedCast<JSArrayBuffer>(
43       Allocate(JSArrayBuffer::kSizeWithEmbedderFields));
44   StoreMapNoWriteBarrier(buffer, map);
45   StoreObjectFieldNoWriteBarrier(buffer, JSArray::kPropertiesOrHashOffset,
46                                  empty_fixed_array);
47   StoreObjectFieldNoWriteBarrier(buffer, JSArray::kElementsOffset,
48                                  empty_fixed_array);
49   // Setup the ArrayBuffer.
50   //  - Set BitField to 0.
51   //  - Set IsExternal and IsDetachable bits of BitFieldSlot.
52   //  - Set the byte_length field to zero.
53   //  - Set backing_store to null/Smi(0).
54   //  - Set extension to null.
55   //  - Set all embedder fields to Smi(0).
56   if (FIELD_SIZE(JSArrayBuffer::kOptionalPaddingOffset) != 0) {
57     DCHECK_EQ(4, FIELD_SIZE(JSArrayBuffer::kOptionalPaddingOffset));
58     StoreObjectFieldNoWriteBarrier(
59         buffer, JSArrayBuffer::kOptionalPaddingOffset, Int32Constant(0));
60   }
61   int32_t bitfield_value = (1 << JSArrayBuffer::IsExternalBit::kShift) |
62                            (1 << JSArrayBuffer::IsDetachableBit::kShift);
63   StoreObjectFieldNoWriteBarrier(buffer, JSArrayBuffer::kBitFieldOffset,
64                                  Int32Constant(bitfield_value));
65 
66   StoreObjectFieldNoWriteBarrier(buffer, JSArrayBuffer::kByteLengthOffset,
67                                  UintPtrConstant(0));
68   StoreSandboxedPointerToObject(buffer, JSArrayBuffer::kBackingStoreOffset,
69                                 EmptyBackingStoreBufferConstant());
70   StoreObjectFieldNoWriteBarrier(buffer, JSArrayBuffer::kExtensionOffset,
71                                  IntPtrConstant(0));
72   for (int offset = JSArrayBuffer::kHeaderSize;
73        offset < JSArrayBuffer::kSizeWithEmbedderFields; offset += kTaggedSize) {
74     // TODO(v8:10391, saelo): Handle external pointers in EmbedderDataSlot
75     StoreObjectFieldNoWriteBarrier(buffer, offset, SmiConstant(0));
76   }
77   return buffer;
78 }
79 
TF_BUILTIN(TypedArrayBaseConstructor,TypedArrayBuiltinsAssembler)80 TF_BUILTIN(TypedArrayBaseConstructor, TypedArrayBuiltinsAssembler) {
81   auto context = Parameter<Context>(Descriptor::kContext);
82   ThrowTypeError(context, MessageTemplate::kConstructAbstractClass,
83                  "TypedArray");
84 }
85 
86 // ES #sec-typedarray-constructors
TF_BUILTIN(TypedArrayConstructor,TypedArrayBuiltinsAssembler)87 TF_BUILTIN(TypedArrayConstructor, TypedArrayBuiltinsAssembler) {
88   auto context = Parameter<Context>(Descriptor::kContext);
89   auto target = Parameter<JSFunction>(Descriptor::kJSTarget);
90   auto new_target = Parameter<Object>(Descriptor::kJSNewTarget);
91   TNode<IntPtrT> argc = ChangeInt32ToIntPtr(
92       UncheckedParameter<Int32T>(Descriptor::kJSActualArgumentsCount));
93   CodeStubArguments args(this, argc);
94   TNode<Object> arg1 = args.GetOptionalArgumentValue(0);
95   TNode<Object> arg2 = args.GetOptionalArgumentValue(1);
96   TNode<Object> arg3 = args.GetOptionalArgumentValue(2);
97 
98   // If NewTarget is undefined, throw a TypeError exception.
99   // All the TypedArray constructors have this as the first step:
100   // https://tc39.github.io/ecma262/#sec-typedarray-constructors
101   Label throwtypeerror(this, Label::kDeferred);
102   GotoIf(IsUndefined(new_target), &throwtypeerror);
103 
104   TNode<Object> result = CallBuiltin(Builtin::kCreateTypedArray, context,
105                                      target, new_target, arg1, arg2, arg3);
106   args.PopAndReturn(result);
107 
108   BIND(&throwtypeerror);
109   {
110     TNode<String> name =
111         CAST(CallRuntime(Runtime::kGetFunctionName, context, target));
112     ThrowTypeError(context, MessageTemplate::kConstructorNotFunction, name);
113   }
114 }
115 
116 // ES6 #sec-get-%typedarray%.prototype.bytelength
TF_BUILTIN(TypedArrayPrototypeByteLength,TypedArrayBuiltinsAssembler)117 TF_BUILTIN(TypedArrayPrototypeByteLength, TypedArrayBuiltinsAssembler) {
118   const char* const kMethodName = "get TypedArray.prototype.byteLength";
119   auto context = Parameter<Context>(Descriptor::kContext);
120   auto receiver = Parameter<Object>(Descriptor::kReceiver);
121 
122   // Check if the {receiver} is actually a JSTypedArray.
123   ThrowIfNotInstanceType(context, receiver, JS_TYPED_ARRAY_TYPE, kMethodName);
124 
125   TNode<JSTypedArray> receiver_array = CAST(receiver);
126   TNode<JSArrayBuffer> receiver_buffer =
127       LoadJSArrayBufferViewBuffer(receiver_array);
128 
129   Label variable_length(this), normal(this);
130   Branch(IsVariableLengthJSArrayBufferView(receiver_array), &variable_length,
131          &normal);
132   BIND(&variable_length);
133   {
134     Return(ChangeUintPtrToTagged(LoadVariableLengthJSTypedArrayByteLength(
135         context, receiver_array, receiver_buffer)));
136   }
137 
138   BIND(&normal);
139   {
140     // Default to zero if the {receiver}s buffer was detached.
141     TNode<UintPtrT> byte_length = Select<UintPtrT>(
142         IsDetachedBuffer(receiver_buffer), [=] { return UintPtrConstant(0); },
143         [=] { return LoadJSArrayBufferViewByteLength(receiver_array); });
144     Return(ChangeUintPtrToTagged(byte_length));
145   }
146 }
147 
148 // ES6 #sec-get-%typedarray%.prototype.byteoffset
TF_BUILTIN(TypedArrayPrototypeByteOffset,TypedArrayBuiltinsAssembler)149 TF_BUILTIN(TypedArrayPrototypeByteOffset, TypedArrayBuiltinsAssembler) {
150   const char* const kMethodName = "get TypedArray.prototype.byteOffset";
151   auto context = Parameter<Context>(Descriptor::kContext);
152   auto receiver = Parameter<Object>(Descriptor::kReceiver);
153 
154   // Check if the {receiver} is actually a JSTypedArray.
155   ThrowIfNotInstanceType(context, receiver, JS_TYPED_ARRAY_TYPE, kMethodName);
156 
157   // Default to zero if the {receiver}s buffer was detached / out of bounds.
158   Label detached_or_oob(this), not_detached_nor_oob(this);
159   IsJSArrayBufferViewDetachedOrOutOfBounds(CAST(receiver), &detached_or_oob,
160                                            &not_detached_nor_oob);
161   BIND(&detached_or_oob);
162   Return(ChangeUintPtrToTagged(UintPtrConstant(0)));
163 
164   BIND(&not_detached_nor_oob);
165   Return(
166       ChangeUintPtrToTagged(LoadJSArrayBufferViewByteOffset(CAST(receiver))));
167 }
168 
169 // ES6 #sec-get-%typedarray%.prototype.length
TF_BUILTIN(TypedArrayPrototypeLength,TypedArrayBuiltinsAssembler)170 TF_BUILTIN(TypedArrayPrototypeLength, TypedArrayBuiltinsAssembler) {
171   const char* const kMethodName = "get TypedArray.prototype.length";
172   auto context = Parameter<Context>(Descriptor::kContext);
173   auto receiver = Parameter<Object>(Descriptor::kReceiver);
174 
175   // Check if the {receiver} is actually a JSTypedArray.
176   ThrowIfNotInstanceType(context, receiver, JS_TYPED_ARRAY_TYPE, kMethodName);
177 
178   TNode<JSTypedArray> receiver_array = CAST(receiver);
179   TVARIABLE(UintPtrT, length);
180   Label detached(this), end(this);
181   length = LoadJSTypedArrayLengthAndCheckDetached(receiver_array, &detached);
182   Return(ChangeUintPtrToTagged(length.value()));
183   BIND(&detached);
184   Return(ChangeUintPtrToTagged(UintPtrConstant(0)));
185 }
186 
IsUint8ElementsKind(TNode<Int32T> kind)187 TNode<BoolT> TypedArrayBuiltinsAssembler::IsUint8ElementsKind(
188     TNode<Int32T> kind) {
189   return Word32Or(
190       Word32Or(Word32Equal(kind, Int32Constant(UINT8_ELEMENTS)),
191                Word32Equal(kind, Int32Constant(UINT8_CLAMPED_ELEMENTS))),
192       Word32Or(
193           Word32Equal(kind, Int32Constant(RAB_GSAB_UINT8_ELEMENTS)),
194           Word32Equal(kind, Int32Constant(RAB_GSAB_UINT8_CLAMPED_ELEMENTS))));
195 }
196 
IsBigInt64ElementsKind(TNode<Int32T> kind)197 TNode<BoolT> TypedArrayBuiltinsAssembler::IsBigInt64ElementsKind(
198     TNode<Int32T> kind) {
199   STATIC_ASSERT(BIGUINT64_ELEMENTS + 1 == BIGINT64_ELEMENTS);
200   return Word32Or(
201       IsElementsKindInRange(kind, BIGUINT64_ELEMENTS, BIGINT64_ELEMENTS),
202       IsElementsKindInRange(kind, RAB_GSAB_BIGUINT64_ELEMENTS,
203                             RAB_GSAB_BIGINT64_ELEMENTS));
204 }
205 
GetTypedArrayElementSize(TNode<Int32T> elements_kind)206 TNode<IntPtrT> TypedArrayBuiltinsAssembler::GetTypedArrayElementSize(
207     TNode<Int32T> elements_kind) {
208   TVARIABLE(IntPtrT, element_size);
209 
210   DispatchTypedArrayByElementsKind(
211       elements_kind,
212       [&](ElementsKind el_kind, int size, int typed_array_fun_index) {
213         element_size = IntPtrConstant(size);
214       });
215 
216   return element_size.value();
217 }
218 
219 TorqueStructTypedArrayElementsInfo
GetTypedArrayElementsInfo(TNode<JSTypedArray> typed_array)220 TypedArrayBuiltinsAssembler::GetTypedArrayElementsInfo(
221     TNode<JSTypedArray> typed_array) {
222   return GetTypedArrayElementsInfo(LoadMap(typed_array));
223 }
224 
225 TorqueStructTypedArrayElementsInfo
GetTypedArrayElementsInfo(TNode<Map> map)226 TypedArrayBuiltinsAssembler::GetTypedArrayElementsInfo(TNode<Map> map) {
227   TNode<Int32T> elements_kind = LoadMapElementsKind(map);
228   TVARIABLE(UintPtrT, var_size_log2);
229   TVARIABLE(Map, var_map);
230   ReadOnlyRoots roots(isolate());
231 
232   DispatchTypedArrayByElementsKind(
233       elements_kind,
234       [&](ElementsKind kind, int size, int typed_array_fun_index) {
235         DCHECK_GT(size, 0);
236         var_size_log2 = UintPtrConstant(ElementsKindToShiftSize(kind));
237       });
238 
239   return TorqueStructTypedArrayElementsInfo{var_size_log2.value(),
240                                             elements_kind};
241 }
242 
GetDefaultConstructor(TNode<Context> context,TNode<JSTypedArray> exemplar)243 TNode<JSFunction> TypedArrayBuiltinsAssembler::GetDefaultConstructor(
244     TNode<Context> context, TNode<JSTypedArray> exemplar) {
245   TVARIABLE(IntPtrT, context_slot);
246   TNode<Int32T> elements_kind = LoadElementsKind(exemplar);
247 
248   DispatchTypedArrayByElementsKind(
249       elements_kind,
250       [&](ElementsKind el_kind, int size, int typed_array_function_index) {
251         context_slot = IntPtrConstant(typed_array_function_index);
252       });
253 
254   return CAST(
255       LoadContextElement(LoadNativeContext(context), context_slot.value()));
256 }
257 
ValidateTypedArray(TNode<Context> context,TNode<Object> obj,const char * method_name)258 TNode<JSTypedArray> TypedArrayBuiltinsAssembler::ValidateTypedArray(
259     TNode<Context> context, TNode<Object> obj, const char* method_name) {
260   // If it is not a typed array, throw
261   ThrowIfNotInstanceType(context, obj, JS_TYPED_ARRAY_TYPE, method_name);
262 
263   // If the typed array's buffer is detached, throw
264   ThrowIfArrayBufferViewBufferIsDetached(context, CAST(obj), method_name);
265 
266   // TODO(v8:11111): Throw if the RAB / GSAB is OOB.
267   return CAST(obj);
268 }
269 
ValidateTypedArrayAndGetLength(TNode<Context> context,TNode<Object> obj,const char * method_name)270 TNode<UintPtrT> TypedArrayBuiltinsAssembler::ValidateTypedArrayAndGetLength(
271     TNode<Context> context, TNode<Object> obj, const char* method_name) {
272   // If it is not a typed array, throw
273   ThrowIfNotInstanceType(context, obj, JS_TYPED_ARRAY_TYPE, method_name);
274 
275   Label detached_or_oob(this), not_detached_nor_oob(this);
276   TNode<UintPtrT> length =
277       LoadJSTypedArrayLengthAndCheckDetached(CAST(obj), &detached_or_oob);
278   Goto(&not_detached_nor_oob);
279 
280   BIND(&detached_or_oob);
281   ThrowTypeError(context, MessageTemplate::kDetachedOperation, method_name);
282 
283   BIND(&not_detached_nor_oob);
284   return length;
285 }
286 
CallCMemmove(TNode<RawPtrT> dest_ptr,TNode<RawPtrT> src_ptr,TNode<UintPtrT> byte_length)287 void TypedArrayBuiltinsAssembler::CallCMemmove(TNode<RawPtrT> dest_ptr,
288                                                TNode<RawPtrT> src_ptr,
289                                                TNode<UintPtrT> byte_length) {
290   TNode<ExternalReference> memmove =
291       ExternalConstant(ExternalReference::libc_memmove_function());
292   CallCFunction(memmove, MachineType::AnyTagged(),
293                 std::make_pair(MachineType::Pointer(), dest_ptr),
294                 std::make_pair(MachineType::Pointer(), src_ptr),
295                 std::make_pair(MachineType::UintPtr(), byte_length));
296 }
297 
CallCRelaxedMemmove(TNode<RawPtrT> dest_ptr,TNode<RawPtrT> src_ptr,TNode<UintPtrT> byte_length)298 void TypedArrayBuiltinsAssembler::CallCRelaxedMemmove(
299     TNode<RawPtrT> dest_ptr, TNode<RawPtrT> src_ptr,
300     TNode<UintPtrT> byte_length) {
301   TNode<ExternalReference> memmove =
302       ExternalConstant(ExternalReference::relaxed_memmove_function());
303   CallCFunction(memmove, MachineType::AnyTagged(),
304                 std::make_pair(MachineType::Pointer(), dest_ptr),
305                 std::make_pair(MachineType::Pointer(), src_ptr),
306                 std::make_pair(MachineType::UintPtr(), byte_length));
307 }
308 
CallCMemcpy(TNode<RawPtrT> dest_ptr,TNode<RawPtrT> src_ptr,TNode<UintPtrT> byte_length)309 void TypedArrayBuiltinsAssembler::CallCMemcpy(TNode<RawPtrT> dest_ptr,
310                                               TNode<RawPtrT> src_ptr,
311                                               TNode<UintPtrT> byte_length) {
312   TNode<ExternalReference> memcpy =
313       ExternalConstant(ExternalReference::libc_memcpy_function());
314   CallCFunction(memcpy, MachineType::AnyTagged(),
315                 std::make_pair(MachineType::Pointer(), dest_ptr),
316                 std::make_pair(MachineType::Pointer(), src_ptr),
317                 std::make_pair(MachineType::UintPtr(), byte_length));
318 }
319 
CallCRelaxedMemcpy(TNode<RawPtrT> dest_ptr,TNode<RawPtrT> src_ptr,TNode<UintPtrT> byte_length)320 void TypedArrayBuiltinsAssembler::CallCRelaxedMemcpy(
321     TNode<RawPtrT> dest_ptr, TNode<RawPtrT> src_ptr,
322     TNode<UintPtrT> byte_length) {
323   TNode<ExternalReference> relaxed_memcpy =
324       ExternalConstant(ExternalReference::relaxed_memcpy_function());
325   CallCFunction(relaxed_memcpy, MachineType::AnyTagged(),
326                 std::make_pair(MachineType::Pointer(), dest_ptr),
327                 std::make_pair(MachineType::Pointer(), src_ptr),
328                 std::make_pair(MachineType::UintPtr(), byte_length));
329 }
330 
CallCMemset(TNode<RawPtrT> dest_ptr,TNode<IntPtrT> value,TNode<UintPtrT> length)331 void TypedArrayBuiltinsAssembler::CallCMemset(TNode<RawPtrT> dest_ptr,
332                                               TNode<IntPtrT> value,
333                                               TNode<UintPtrT> length) {
334   TNode<ExternalReference> memset =
335       ExternalConstant(ExternalReference::libc_memset_function());
336   CallCFunction(memset, MachineType::AnyTagged(),
337                 std::make_pair(MachineType::Pointer(), dest_ptr),
338                 std::make_pair(MachineType::IntPtr(), value),
339                 std::make_pair(MachineType::UintPtr(), length));
340 }
341 
342 void TypedArrayBuiltinsAssembler::
CallCCopyFastNumberJSArrayElementsToTypedArray(TNode<Context> context,TNode<JSArray> source,TNode<JSTypedArray> dest,TNode<UintPtrT> source_length,TNode<UintPtrT> offset)343     CallCCopyFastNumberJSArrayElementsToTypedArray(
344         TNode<Context> context, TNode<JSArray> source, TNode<JSTypedArray> dest,
345         TNode<UintPtrT> source_length, TNode<UintPtrT> offset) {
346   CSA_DCHECK(this,
347              Word32BinaryNot(IsBigInt64ElementsKind(LoadElementsKind(dest))));
348   TNode<ExternalReference> f = ExternalConstant(
349       ExternalReference::copy_fast_number_jsarray_elements_to_typed_array());
350   CallCFunction(f, MachineType::AnyTagged(),
351                 std::make_pair(MachineType::AnyTagged(), context),
352                 std::make_pair(MachineType::AnyTagged(), source),
353                 std::make_pair(MachineType::AnyTagged(), dest),
354                 std::make_pair(MachineType::UintPtr(), source_length),
355                 std::make_pair(MachineType::UintPtr(), offset));
356 }
357 
CallCCopyTypedArrayElementsToTypedArray(TNode<JSTypedArray> source,TNode<JSTypedArray> dest,TNode<UintPtrT> source_length,TNode<UintPtrT> offset)358 void TypedArrayBuiltinsAssembler::CallCCopyTypedArrayElementsToTypedArray(
359     TNode<JSTypedArray> source, TNode<JSTypedArray> dest,
360     TNode<UintPtrT> source_length, TNode<UintPtrT> offset) {
361   TNode<ExternalReference> f = ExternalConstant(
362       ExternalReference::copy_typed_array_elements_to_typed_array());
363   CallCFunction(f, MachineType::AnyTagged(),
364                 std::make_pair(MachineType::AnyTagged(), source),
365                 std::make_pair(MachineType::AnyTagged(), dest),
366                 std::make_pair(MachineType::UintPtr(), source_length),
367                 std::make_pair(MachineType::UintPtr(), offset));
368 }
369 
CallCCopyTypedArrayElementsSlice(TNode<JSTypedArray> source,TNode<JSTypedArray> dest,TNode<UintPtrT> start,TNode<UintPtrT> end)370 void TypedArrayBuiltinsAssembler::CallCCopyTypedArrayElementsSlice(
371     TNode<JSTypedArray> source, TNode<JSTypedArray> dest, TNode<UintPtrT> start,
372     TNode<UintPtrT> end) {
373   TNode<ExternalReference> f =
374       ExternalConstant(ExternalReference::copy_typed_array_elements_slice());
375   CallCFunction(f, MachineType::AnyTagged(),
376                 std::make_pair(MachineType::AnyTagged(), source),
377                 std::make_pair(MachineType::AnyTagged(), dest),
378                 std::make_pair(MachineType::UintPtr(), start),
379                 std::make_pair(MachineType::UintPtr(), end));
380 }
381 
DispatchTypedArrayByElementsKind(TNode<Word32T> elements_kind,const TypedArraySwitchCase & case_function)382 void TypedArrayBuiltinsAssembler::DispatchTypedArrayByElementsKind(
383     TNode<Word32T> elements_kind, const TypedArraySwitchCase& case_function) {
384   Label next(this), if_unknown_type(this, Label::kDeferred);
385 
386   int32_t elements_kinds[] = {
387 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) TYPE##_ELEMENTS,
388       TYPED_ARRAYS(TYPED_ARRAY_CASE) RAB_GSAB_TYPED_ARRAYS(TYPED_ARRAY_CASE)
389 #undef TYPED_ARRAY_CASE
390   };
391 
392 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) Label if_##type##array(this);
393   TYPED_ARRAYS(TYPED_ARRAY_CASE)
394   RAB_GSAB_TYPED_ARRAYS(TYPED_ARRAY_CASE)
395 #undef TYPED_ARRAY_CASE
396 
397   Label* elements_kind_labels[] = {
398 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) &if_##type##array,
399       TYPED_ARRAYS(TYPED_ARRAY_CASE) RAB_GSAB_TYPED_ARRAYS(TYPED_ARRAY_CASE)
400 #undef TYPED_ARRAY_CASE
401   };
402   STATIC_ASSERT(arraysize(elements_kinds) == arraysize(elements_kind_labels));
403 
404   Switch(elements_kind, &if_unknown_type, elements_kinds, elements_kind_labels,
405          arraysize(elements_kinds));
406 
407 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype)   \
408   BIND(&if_##type##array);                          \
409   {                                                 \
410     case_function(TYPE##_ELEMENTS, sizeof(ctype),   \
411                   Context::TYPE##_ARRAY_FUN_INDEX); \
412     Goto(&next);                                    \
413   }
414   TYPED_ARRAYS(TYPED_ARRAY_CASE)
415 #undef TYPED_ARRAY_CASE
416 
417 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, NON_RAB_GSAB_TYPE) \
418   BIND(&if_##type##array);                                           \
419   {                                                                  \
420     case_function(TYPE##_ELEMENTS, sizeof(ctype),                    \
421                   Context::NON_RAB_GSAB_TYPE##_ARRAY_FUN_INDEX);     \
422     Goto(&next);                                                     \
423   }
424   RAB_GSAB_TYPED_ARRAYS_WITH_NON_RAB_GSAB_ELEMENTS_KIND(TYPED_ARRAY_CASE)
425 #undef TYPED_ARRAY_CASE
426 
427   BIND(&if_unknown_type);
428   Unreachable();
429 
430   BIND(&next);
431 }
432 
SetJSTypedArrayOnHeapDataPtr(TNode<JSTypedArray> holder,TNode<ByteArray> base,TNode<UintPtrT> offset)433 void TypedArrayBuiltinsAssembler::SetJSTypedArrayOnHeapDataPtr(
434     TNode<JSTypedArray> holder, TNode<ByteArray> base, TNode<UintPtrT> offset) {
435   offset = UintPtrAdd(UintPtrConstant(ByteArray::kHeaderSize - kHeapObjectTag),
436                       offset);
437   if (COMPRESS_POINTERS_BOOL) {
438     TNode<IntPtrT> full_base = Signed(BitcastTaggedToWord(base));
439     TNode<Int32T> compressed_base = TruncateIntPtrToInt32(full_base);
440     // TODO(v8:9706): Add a way to directly use kRootRegister value.
441     TNode<IntPtrT> ptr_compr_cage_base =
442         IntPtrSub(full_base, Signed(ChangeUint32ToWord(compressed_base)));
443     // Add JSTypedArray::ExternalPointerCompensationForOnHeapArray() to offset.
444     // See JSTypedArray::AddExternalPointerCompensationForDeserialization().
445     DCHECK_EQ(
446         isolate()->cage_base(),
447         JSTypedArray::ExternalPointerCompensationForOnHeapArray(isolate()));
448     offset = Unsigned(IntPtrAdd(offset, ptr_compr_cage_base));
449   }
450 
451   StoreJSTypedArrayBasePointer(holder, base);
452   StoreJSTypedArrayExternalPointerPtr(holder, ReinterpretCast<RawPtrT>(offset));
453 }
454 
SetJSTypedArrayOffHeapDataPtr(TNode<JSTypedArray> holder,TNode<RawPtrT> base,TNode<UintPtrT> offset)455 void TypedArrayBuiltinsAssembler::SetJSTypedArrayOffHeapDataPtr(
456     TNode<JSTypedArray> holder, TNode<RawPtrT> base, TNode<UintPtrT> offset) {
457   StoreObjectFieldNoWriteBarrier(holder, JSTypedArray::kBasePointerOffset,
458                                  SmiConstant(0));
459 
460   base = RawPtrAdd(base, Signed(offset));
461   StoreJSTypedArrayExternalPointerPtr(holder, base);
462 }
463 
StoreJSTypedArrayElementFromNumeric(TNode<Context> context,TNode<JSTypedArray> typed_array,TNode<UintPtrT> index,TNode<Numeric> value,ElementsKind elements_kind)464 void TypedArrayBuiltinsAssembler::StoreJSTypedArrayElementFromNumeric(
465     TNode<Context> context, TNode<JSTypedArray> typed_array,
466     TNode<UintPtrT> index, TNode<Numeric> value, ElementsKind elements_kind) {
467   TNode<RawPtrT> data_ptr = LoadJSTypedArrayDataPtr(typed_array);
468   switch (elements_kind) {
469     case UINT8_ELEMENTS:
470     case UINT8_CLAMPED_ELEMENTS:
471     case INT8_ELEMENTS:
472     case UINT16_ELEMENTS:
473     case INT16_ELEMENTS:
474       StoreElement(data_ptr, elements_kind, index, SmiToInt32(CAST(value)));
475       break;
476     case UINT32_ELEMENTS:
477     case INT32_ELEMENTS:
478       StoreElement(data_ptr, elements_kind, index,
479                    TruncateTaggedToWord32(context, value));
480       break;
481     case FLOAT32_ELEMENTS:
482       StoreElement(data_ptr, elements_kind, index,
483                    TruncateFloat64ToFloat32(LoadHeapNumberValue(CAST(value))));
484       break;
485     case FLOAT64_ELEMENTS:
486       StoreElement(data_ptr, elements_kind, index,
487                    LoadHeapNumberValue(CAST(value)));
488       break;
489     case BIGUINT64_ELEMENTS:
490     case BIGINT64_ELEMENTS:
491       StoreElement(data_ptr, elements_kind, index,
492                    UncheckedCast<BigInt>(value));
493       break;
494     default:
495       UNREACHABLE();
496   }
497 }
498 
499 template <typename TValue>
StoreJSTypedArrayElementFromPreparedValue(TNode<Context> context,TNode<JSTypedArray> typed_array,TNode<UintPtrT> index,TNode<TValue> prepared_value,ElementsKind elements_kind,Label * if_detached)500 void TypedArrayBuiltinsAssembler::StoreJSTypedArrayElementFromPreparedValue(
501     TNode<Context> context, TNode<JSTypedArray> typed_array,
502     TNode<UintPtrT> index, TNode<TValue> prepared_value,
503     ElementsKind elements_kind, Label* if_detached) {
504   static_assert(
505       std::is_same<TValue, Word32T>::value ||
506           std::is_same<TValue, Float32T>::value ||
507           std::is_same<TValue, Float64T>::value ||
508           std::is_same<TValue, BigInt>::value,
509       "Only Word32T, Float32T, Float64T or BigInt values are allowed");
510   // ToNumber/ToBigInt may execute JavaScript code, which could detach
511   // the array's buffer.
512   TNode<JSArrayBuffer> buffer = LoadJSArrayBufferViewBuffer(typed_array);
513   GotoIf(IsDetachedBuffer(buffer), if_detached);
514 
515   TNode<RawPtrT> data_ptr = LoadJSTypedArrayDataPtr(typed_array);
516   StoreElement(data_ptr, elements_kind, index, prepared_value);
517 }
518 
StoreJSTypedArrayElementFromTagged(TNode<Context> context,TNode<JSTypedArray> typed_array,TNode<UintPtrT> index,TNode<Object> value,ElementsKind elements_kind,Label * if_detached)519 void TypedArrayBuiltinsAssembler::StoreJSTypedArrayElementFromTagged(
520     TNode<Context> context, TNode<JSTypedArray> typed_array,
521     TNode<UintPtrT> index, TNode<Object> value, ElementsKind elements_kind,
522     Label* if_detached) {
523   switch (elements_kind) {
524     case UINT8_ELEMENTS:
525     case INT8_ELEMENTS:
526     case UINT16_ELEMENTS:
527     case INT16_ELEMENTS:
528     case UINT32_ELEMENTS:
529     case INT32_ELEMENTS:
530     case UINT8_CLAMPED_ELEMENTS: {
531       auto prepared_value = PrepareValueForWriteToTypedArray<Word32T>(
532           value, elements_kind, context);
533       StoreJSTypedArrayElementFromPreparedValue(context, typed_array, index,
534                                                 prepared_value, elements_kind,
535                                                 if_detached);
536       break;
537     }
538     case FLOAT32_ELEMENTS: {
539       auto prepared_value = PrepareValueForWriteToTypedArray<Float32T>(
540           value, elements_kind, context);
541       StoreJSTypedArrayElementFromPreparedValue(context, typed_array, index,
542                                                 prepared_value, elements_kind,
543                                                 if_detached);
544       break;
545     }
546     case FLOAT64_ELEMENTS: {
547       auto prepared_value = PrepareValueForWriteToTypedArray<Float64T>(
548           value, elements_kind, context);
549       StoreJSTypedArrayElementFromPreparedValue(context, typed_array, index,
550                                                 prepared_value, elements_kind,
551                                                 if_detached);
552       break;
553     }
554     case BIGINT64_ELEMENTS:
555     case BIGUINT64_ELEMENTS: {
556       auto prepared_value = PrepareValueForWriteToTypedArray<BigInt>(
557           value, elements_kind, context);
558       StoreJSTypedArrayElementFromPreparedValue(context, typed_array, index,
559                                                 prepared_value, elements_kind,
560                                                 if_detached);
561       break;
562     }
563     default:
564       UNREACHABLE();
565   }
566 }
567 
568 // ES #sec-get-%typedarray%.prototype-@@tostringtag
TF_BUILTIN(TypedArrayPrototypeToStringTag,TypedArrayBuiltinsAssembler)569 TF_BUILTIN(TypedArrayPrototypeToStringTag, TypedArrayBuiltinsAssembler) {
570   auto receiver = Parameter<Object>(Descriptor::kReceiver);
571   Label if_receiverisheapobject(this), return_undefined(this);
572   Branch(TaggedIsSmi(receiver), &return_undefined, &if_receiverisheapobject);
573 
574   // Dispatch on the elements kind, offset by
575   // FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND.
576   size_t const kTypedElementsKindCount = LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND -
577                                          FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND +
578                                          1;
579 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) \
580   Label return_##type##array(this);               \
581   BIND(&return_##type##array);                    \
582   Return(StringConstant(#Type "Array"));
583   TYPED_ARRAYS(TYPED_ARRAY_CASE)
584 #undef TYPED_ARRAY_CASE
585   Label* elements_kind_labels[kTypedElementsKindCount] = {
586 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) &return_##type##array,
587       TYPED_ARRAYS(TYPED_ARRAY_CASE)
588 #undef TYPED_ARRAY_CASE
589   };
590   int32_t elements_kinds[kTypedElementsKindCount] = {
591 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) \
592   TYPE##_ELEMENTS - FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND,
593       TYPED_ARRAYS(TYPED_ARRAY_CASE)
594 #undef TYPED_ARRAY_CASE
595   };
596 
597   // We offset the dispatch by FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND, so that
598   // this can be turned into a non-sparse table switch for ideal performance.
599   BIND(&if_receiverisheapobject);
600   TNode<HeapObject> receiver_heap_object = CAST(receiver);
601   TNode<Int32T> elements_kind =
602       Int32Sub(LoadElementsKind(receiver_heap_object),
603                Int32Constant(FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND));
604   Switch(elements_kind, &return_undefined, elements_kinds, elements_kind_labels,
605          kTypedElementsKindCount);
606 
607   BIND(&return_undefined);
608   Return(UndefinedConstant());
609 }
610 }  // namespace internal
611 }  // namespace v8
612