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 ¬_detached_nor_oob);
161 BIND(&detached_or_oob);
162 Return(ChangeUintPtrToTagged(UintPtrConstant(0)));
163
164 BIND(¬_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(¬_detached_nor_oob);
279
280 BIND(&detached_or_oob);
281 ThrowTypeError(context, MessageTemplate::kDetachedOperation, method_name);
282
283 BIND(¬_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