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
15 namespace v8 {
16 namespace internal {
17
18 using compiler::Node;
19
20 // -----------------------------------------------------------------------------
21 // ES6 section 22.2 TypedArray Objects
22
23 // Sets the embedder fields to 0 for a TypedArray which is under construction.
SetupTypedArrayEmbedderFields(TNode<JSTypedArray> holder)24 void TypedArrayBuiltinsAssembler::SetupTypedArrayEmbedderFields(
25 TNode<JSTypedArray> holder) {
26 for (int offset = JSTypedArray::kHeaderSize;
27 offset < JSTypedArray::kSizeWithEmbedderFields; offset += kTaggedSize) {
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,TNode<UintPtrT> byte_length)35 TNode<JSArrayBuffer> TypedArrayBuiltinsAssembler::AllocateEmptyOnHeapBuffer(
36 TNode<Context> context, TNode<UintPtrT> byte_length) {
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 byte_length.
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 byte_length);
68 StoreObjectFieldNoWriteBarrier(buffer, JSArrayBuffer::kBackingStoreOffset,
69 IntPtrConstant(0));
70 if (V8_ARRAY_BUFFER_EXTENSION_BOOL) {
71 StoreObjectFieldNoWriteBarrier(buffer, JSArrayBuffer::kExtensionOffset,
72 IntPtrConstant(0));
73 }
74 for (int offset = JSArrayBuffer::kHeaderSize;
75 offset < JSArrayBuffer::kSizeWithEmbedderFields; offset += kTaggedSize) {
76 StoreObjectFieldNoWriteBarrier(buffer, offset, SmiConstant(0));
77 }
78 return buffer;
79 }
80
TF_BUILTIN(TypedArrayBaseConstructor,TypedArrayBuiltinsAssembler)81 TF_BUILTIN(TypedArrayBaseConstructor, TypedArrayBuiltinsAssembler) {
82 TNode<Context> context = CAST(Parameter(Descriptor::kContext));
83 ThrowTypeError(context, MessageTemplate::kConstructAbstractClass,
84 "TypedArray");
85 }
86
87 // ES #sec-typedarray-constructors
TF_BUILTIN(TypedArrayConstructor,TypedArrayBuiltinsAssembler)88 TF_BUILTIN(TypedArrayConstructor, TypedArrayBuiltinsAssembler) {
89 TNode<Context> context = CAST(Parameter(Descriptor::kContext));
90 TNode<JSFunction> target = CAST(Parameter(Descriptor::kJSTarget));
91 TNode<Object> new_target = CAST(Parameter(Descriptor::kJSNewTarget));
92 TNode<IntPtrT> argc = ChangeInt32ToIntPtr(
93 UncheckedCast<Int32T>(Parameter(Descriptor::kJSActualArgumentsCount)));
94 CodeStubArguments args(this, argc);
95 TNode<Object> arg1 = args.GetOptionalArgumentValue(0);
96 TNode<Object> arg2 = args.GetOptionalArgumentValue(1);
97 TNode<Object> arg3 = args.GetOptionalArgumentValue(2);
98
99 // If NewTarget is undefined, throw a TypeError exception.
100 // All the TypedArray constructors have this as the first step:
101 // https://tc39.github.io/ecma262/#sec-typedarray-constructors
102 Label throwtypeerror(this, Label::kDeferred);
103 GotoIf(IsUndefined(new_target), &throwtypeerror);
104
105 TNode<Object> result = CallBuiltin(Builtins::kCreateTypedArray, context,
106 target, new_target, arg1, arg2, arg3);
107 args.PopAndReturn(result);
108
109 BIND(&throwtypeerror);
110 {
111 TNode<String> name =
112 CAST(CallRuntime(Runtime::kGetFunctionName, context, target));
113 ThrowTypeError(context, MessageTemplate::kConstructorNotFunction, name);
114 }
115 }
116
117 // ES6 #sec-get-%typedarray%.prototype.bytelength
TF_BUILTIN(TypedArrayPrototypeByteLength,TypedArrayBuiltinsAssembler)118 TF_BUILTIN(TypedArrayPrototypeByteLength, TypedArrayBuiltinsAssembler) {
119 const char* const kMethodName = "get TypedArray.prototype.byteLength";
120 TNode<Context> context = CAST(Parameter(Descriptor::kContext));
121 TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
122
123 // Check if the {receiver} is actually a JSTypedArray.
124 ThrowIfNotInstanceType(context, receiver, JS_TYPED_ARRAY_TYPE, kMethodName);
125
126 // Default to zero if the {receiver}s buffer was detached.
127 TNode<JSArrayBuffer> receiver_buffer =
128 LoadJSArrayBufferViewBuffer(CAST(receiver));
129 TNode<UintPtrT> byte_length = Select<UintPtrT>(
130 IsDetachedBuffer(receiver_buffer), [=] { return UintPtrConstant(0); },
131 [=] { return LoadJSArrayBufferViewByteLength(CAST(receiver)); });
132 Return(ChangeUintPtrToTagged(byte_length));
133 }
134
135 // ES6 #sec-get-%typedarray%.prototype.byteoffset
TF_BUILTIN(TypedArrayPrototypeByteOffset,TypedArrayBuiltinsAssembler)136 TF_BUILTIN(TypedArrayPrototypeByteOffset, TypedArrayBuiltinsAssembler) {
137 const char* const kMethodName = "get TypedArray.prototype.byteOffset";
138 TNode<Context> context = CAST(Parameter(Descriptor::kContext));
139 TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
140
141 // Check if the {receiver} is actually a JSTypedArray.
142 ThrowIfNotInstanceType(context, receiver, JS_TYPED_ARRAY_TYPE, kMethodName);
143
144 // Default to zero if the {receiver}s buffer was detached.
145 TNode<JSArrayBuffer> receiver_buffer =
146 LoadJSArrayBufferViewBuffer(CAST(receiver));
147 TNode<UintPtrT> byte_offset = Select<UintPtrT>(
148 IsDetachedBuffer(receiver_buffer), [=] { return UintPtrConstant(0); },
149 [=] { return LoadJSArrayBufferViewByteOffset(CAST(receiver)); });
150 Return(ChangeUintPtrToTagged(byte_offset));
151 }
152
153 // ES6 #sec-get-%typedarray%.prototype.length
TF_BUILTIN(TypedArrayPrototypeLength,TypedArrayBuiltinsAssembler)154 TF_BUILTIN(TypedArrayPrototypeLength, TypedArrayBuiltinsAssembler) {
155 const char* const kMethodName = "get TypedArray.prototype.length";
156 TNode<Context> context = CAST(Parameter(Descriptor::kContext));
157 TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
158
159 // Check if the {receiver} is actually a JSTypedArray.
160 ThrowIfNotInstanceType(context, receiver, JS_TYPED_ARRAY_TYPE, kMethodName);
161
162 // Default to zero if the {receiver}s buffer was detached.
163 TNode<JSArrayBuffer> receiver_buffer =
164 LoadJSArrayBufferViewBuffer(CAST(receiver));
165 TNode<UintPtrT> length = Select<UintPtrT>(
166 IsDetachedBuffer(receiver_buffer), [=] { return UintPtrConstant(0); },
167 [=] { return LoadJSTypedArrayLength(CAST(receiver)); });
168 Return(ChangeUintPtrToTagged(length));
169 }
170
IsUint8ElementsKind(TNode<Int32T> kind)171 TNode<BoolT> TypedArrayBuiltinsAssembler::IsUint8ElementsKind(
172 TNode<Int32T> kind) {
173 return Word32Or(Word32Equal(kind, Int32Constant(UINT8_ELEMENTS)),
174 Word32Equal(kind, Int32Constant(UINT8_CLAMPED_ELEMENTS)));
175 }
176
IsBigInt64ElementsKind(TNode<Int32T> kind)177 TNode<BoolT> TypedArrayBuiltinsAssembler::IsBigInt64ElementsKind(
178 TNode<Int32T> kind) {
179 STATIC_ASSERT(BIGUINT64_ELEMENTS + 1 == BIGINT64_ELEMENTS);
180 return IsElementsKindInRange(kind, BIGUINT64_ELEMENTS, BIGINT64_ELEMENTS);
181 }
182
GetTypedArrayElementSize(TNode<Int32T> elements_kind)183 TNode<IntPtrT> TypedArrayBuiltinsAssembler::GetTypedArrayElementSize(
184 TNode<Int32T> elements_kind) {
185 TVARIABLE(IntPtrT, element_size);
186
187 DispatchTypedArrayByElementsKind(
188 elements_kind,
189 [&](ElementsKind el_kind, int size, int typed_array_fun_index) {
190 element_size = IntPtrConstant(size);
191 });
192
193 return element_size.value();
194 }
195
196 TorqueStructTypedArrayElementsInfo
GetTypedArrayElementsInfo(TNode<JSTypedArray> typed_array)197 TypedArrayBuiltinsAssembler::GetTypedArrayElementsInfo(
198 TNode<JSTypedArray> typed_array) {
199 return GetTypedArrayElementsInfo(LoadMap(typed_array));
200 }
201
202 TorqueStructTypedArrayElementsInfo
GetTypedArrayElementsInfo(TNode<Map> map)203 TypedArrayBuiltinsAssembler::GetTypedArrayElementsInfo(TNode<Map> map) {
204 TNode<Int32T> elements_kind = LoadMapElementsKind(map);
205 TVARIABLE(UintPtrT, var_size_log2);
206 TVARIABLE(Map, var_map);
207 ReadOnlyRoots roots(isolate());
208
209 DispatchTypedArrayByElementsKind(
210 elements_kind,
211 [&](ElementsKind kind, int size, int typed_array_fun_index) {
212 DCHECK_GT(size, 0);
213 var_size_log2 = UintPtrConstant(ElementsKindToShiftSize(kind));
214 });
215
216 return TorqueStructTypedArrayElementsInfo{var_size_log2.value(),
217 elements_kind};
218 }
219
GetDefaultConstructor(TNode<Context> context,TNode<JSTypedArray> exemplar)220 TNode<JSFunction> TypedArrayBuiltinsAssembler::GetDefaultConstructor(
221 TNode<Context> context, TNode<JSTypedArray> exemplar) {
222 TVARIABLE(IntPtrT, context_slot);
223 TNode<Int32T> elements_kind = LoadElementsKind(exemplar);
224
225 DispatchTypedArrayByElementsKind(
226 elements_kind,
227 [&](ElementsKind el_kind, int size, int typed_array_function_index) {
228 context_slot = IntPtrConstant(typed_array_function_index);
229 });
230
231 return CAST(
232 LoadContextElement(LoadNativeContext(context), context_slot.value()));
233 }
234
GetBuffer(TNode<Context> context,TNode<JSTypedArray> array)235 TNode<JSArrayBuffer> TypedArrayBuiltinsAssembler::GetBuffer(
236 TNode<Context> context, TNode<JSTypedArray> array) {
237 Label call_runtime(this), done(this);
238 TVARIABLE(Object, var_result);
239
240 TNode<JSArrayBuffer> buffer = LoadJSArrayBufferViewBuffer(array);
241 GotoIf(IsDetachedBuffer(buffer), &call_runtime);
242 TNode<RawPtrT> backing_store = LoadJSArrayBufferBackingStore(buffer);
243 GotoIf(WordEqual(backing_store, IntPtrConstant(0)), &call_runtime);
244 var_result = buffer;
245 Goto(&done);
246
247 BIND(&call_runtime);
248 {
249 var_result = CallRuntime(Runtime::kTypedArrayGetBuffer, context, array);
250 Goto(&done);
251 }
252
253 BIND(&done);
254 return CAST(var_result.value());
255 }
256
ValidateTypedArray(TNode<Context> context,TNode<Object> obj,const char * method_name)257 TNode<JSTypedArray> TypedArrayBuiltinsAssembler::ValidateTypedArray(
258 TNode<Context> context, TNode<Object> obj, const char* method_name) {
259 // If it is not a typed array, throw
260 ThrowIfNotInstanceType(context, obj, JS_TYPED_ARRAY_TYPE, method_name);
261
262 // If the typed array's buffer is detached, throw
263 ThrowIfArrayBufferViewBufferIsDetached(context, CAST(obj), method_name);
264
265 return CAST(obj);
266 }
267
CallCMemmove(TNode<RawPtrT> dest_ptr,TNode<RawPtrT> src_ptr,TNode<UintPtrT> byte_length)268 void TypedArrayBuiltinsAssembler::CallCMemmove(TNode<RawPtrT> dest_ptr,
269 TNode<RawPtrT> src_ptr,
270 TNode<UintPtrT> byte_length) {
271 TNode<ExternalReference> memmove =
272 ExternalConstant(ExternalReference::libc_memmove_function());
273 CallCFunction(memmove, MachineType::AnyTagged(),
274 std::make_pair(MachineType::Pointer(), dest_ptr),
275 std::make_pair(MachineType::Pointer(), src_ptr),
276 std::make_pair(MachineType::UintPtr(), byte_length));
277 }
278
CallCMemcpy(TNode<RawPtrT> dest_ptr,TNode<RawPtrT> src_ptr,TNode<UintPtrT> byte_length)279 void TypedArrayBuiltinsAssembler::CallCMemcpy(TNode<RawPtrT> dest_ptr,
280 TNode<RawPtrT> src_ptr,
281 TNode<UintPtrT> byte_length) {
282 TNode<ExternalReference> memcpy =
283 ExternalConstant(ExternalReference::libc_memcpy_function());
284 CallCFunction(memcpy, MachineType::AnyTagged(),
285 std::make_pair(MachineType::Pointer(), dest_ptr),
286 std::make_pair(MachineType::Pointer(), src_ptr),
287 std::make_pair(MachineType::UintPtr(), byte_length));
288 }
289
CallCMemset(TNode<RawPtrT> dest_ptr,TNode<IntPtrT> value,TNode<UintPtrT> length)290 void TypedArrayBuiltinsAssembler::CallCMemset(TNode<RawPtrT> dest_ptr,
291 TNode<IntPtrT> value,
292 TNode<UintPtrT> length) {
293 TNode<ExternalReference> memset =
294 ExternalConstant(ExternalReference::libc_memset_function());
295 CallCFunction(memset, MachineType::AnyTagged(),
296 std::make_pair(MachineType::Pointer(), dest_ptr),
297 std::make_pair(MachineType::IntPtr(), value),
298 std::make_pair(MachineType::UintPtr(), length));
299 }
300
301 void TypedArrayBuiltinsAssembler::
CallCCopyFastNumberJSArrayElementsToTypedArray(TNode<Context> context,TNode<JSArray> source,TNode<JSTypedArray> dest,TNode<UintPtrT> source_length,TNode<UintPtrT> offset)302 CallCCopyFastNumberJSArrayElementsToTypedArray(
303 TNode<Context> context, TNode<JSArray> source, TNode<JSTypedArray> dest,
304 TNode<UintPtrT> source_length, TNode<UintPtrT> offset) {
305 CSA_ASSERT(this,
306 Word32BinaryNot(IsBigInt64ElementsKind(LoadElementsKind(dest))));
307 TNode<ExternalReference> f = ExternalConstant(
308 ExternalReference::copy_fast_number_jsarray_elements_to_typed_array());
309 CallCFunction(f, MachineType::AnyTagged(),
310 std::make_pair(MachineType::AnyTagged(), context),
311 std::make_pair(MachineType::AnyTagged(), source),
312 std::make_pair(MachineType::AnyTagged(), dest),
313 std::make_pair(MachineType::UintPtr(), source_length),
314 std::make_pair(MachineType::UintPtr(), offset));
315 }
316
CallCCopyTypedArrayElementsToTypedArray(TNode<JSTypedArray> source,TNode<JSTypedArray> dest,TNode<UintPtrT> source_length,TNode<UintPtrT> offset)317 void TypedArrayBuiltinsAssembler::CallCCopyTypedArrayElementsToTypedArray(
318 TNode<JSTypedArray> source, TNode<JSTypedArray> dest,
319 TNode<UintPtrT> source_length, TNode<UintPtrT> offset) {
320 TNode<ExternalReference> f = ExternalConstant(
321 ExternalReference::copy_typed_array_elements_to_typed_array());
322 CallCFunction(f, MachineType::AnyTagged(),
323 std::make_pair(MachineType::AnyTagged(), source),
324 std::make_pair(MachineType::AnyTagged(), dest),
325 std::make_pair(MachineType::UintPtr(), source_length),
326 std::make_pair(MachineType::UintPtr(), offset));
327 }
328
CallCCopyTypedArrayElementsSlice(TNode<JSTypedArray> source,TNode<JSTypedArray> dest,TNode<UintPtrT> start,TNode<UintPtrT> end)329 void TypedArrayBuiltinsAssembler::CallCCopyTypedArrayElementsSlice(
330 TNode<JSTypedArray> source, TNode<JSTypedArray> dest, TNode<UintPtrT> start,
331 TNode<UintPtrT> end) {
332 TNode<ExternalReference> f =
333 ExternalConstant(ExternalReference::copy_typed_array_elements_slice());
334 CallCFunction(f, MachineType::AnyTagged(),
335 std::make_pair(MachineType::AnyTagged(), source),
336 std::make_pair(MachineType::AnyTagged(), dest),
337 std::make_pair(MachineType::UintPtr(), start),
338 std::make_pair(MachineType::UintPtr(), end));
339 }
340
DispatchTypedArrayByElementsKind(TNode<Word32T> elements_kind,const TypedArraySwitchCase & case_function)341 void TypedArrayBuiltinsAssembler::DispatchTypedArrayByElementsKind(
342 TNode<Word32T> elements_kind, const TypedArraySwitchCase& case_function) {
343 Label next(this), if_unknown_type(this, Label::kDeferred);
344
345 int32_t elements_kinds[] = {
346 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) TYPE##_ELEMENTS,
347 TYPED_ARRAYS(TYPED_ARRAY_CASE)
348 #undef TYPED_ARRAY_CASE
349 };
350
351 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) Label if_##type##array(this);
352 TYPED_ARRAYS(TYPED_ARRAY_CASE)
353 #undef TYPED_ARRAY_CASE
354
355 Label* elements_kind_labels[] = {
356 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) &if_##type##array,
357 TYPED_ARRAYS(TYPED_ARRAY_CASE)
358 #undef TYPED_ARRAY_CASE
359 };
360 STATIC_ASSERT(arraysize(elements_kinds) == arraysize(elements_kind_labels));
361
362 Switch(elements_kind, &if_unknown_type, elements_kinds, elements_kind_labels,
363 arraysize(elements_kinds));
364
365 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) \
366 BIND(&if_##type##array); \
367 { \
368 case_function(TYPE##_ELEMENTS, sizeof(ctype), \
369 Context::TYPE##_ARRAY_FUN_INDEX); \
370 Goto(&next); \
371 }
372 TYPED_ARRAYS(TYPED_ARRAY_CASE)
373 #undef TYPED_ARRAY_CASE
374
375 BIND(&if_unknown_type);
376 Unreachable();
377
378 BIND(&next);
379 }
380
SetJSTypedArrayOnHeapDataPtr(TNode<JSTypedArray> holder,TNode<ByteArray> base,TNode<UintPtrT> offset)381 void TypedArrayBuiltinsAssembler::SetJSTypedArrayOnHeapDataPtr(
382 TNode<JSTypedArray> holder, TNode<ByteArray> base, TNode<UintPtrT> offset) {
383 offset = UintPtrAdd(UintPtrConstant(ByteArray::kHeaderSize - kHeapObjectTag),
384 offset);
385 if (COMPRESS_POINTERS_BOOL) {
386 TNode<IntPtrT> full_base = Signed(BitcastTaggedToWord(base));
387 TNode<Int32T> compressed_base = TruncateIntPtrToInt32(full_base);
388 // TODO(v8:9706): Add a way to directly use kRootRegister value.
389 TNode<IntPtrT> isolate_root =
390 IntPtrSub(full_base, Signed(ChangeUint32ToWord(compressed_base)));
391 // Add JSTypedArray::ExternalPointerCompensationForOnHeapArray() to offset.
392 DCHECK_EQ(
393 isolate()->isolate_root(),
394 JSTypedArray::ExternalPointerCompensationForOnHeapArray(isolate()));
395 // See JSTypedArray::SetOnHeapDataPtr() for details.
396 offset = Unsigned(IntPtrAdd(offset, isolate_root));
397 }
398
399 StoreObjectField(holder, JSTypedArray::kBasePointerOffset, base);
400 StoreObjectFieldNoWriteBarrier<UintPtrT>(
401 holder, JSTypedArray::kExternalPointerOffset, offset);
402 }
403
SetJSTypedArrayOffHeapDataPtr(TNode<JSTypedArray> holder,TNode<RawPtrT> base,TNode<UintPtrT> offset)404 void TypedArrayBuiltinsAssembler::SetJSTypedArrayOffHeapDataPtr(
405 TNode<JSTypedArray> holder, TNode<RawPtrT> base, TNode<UintPtrT> offset) {
406 StoreObjectFieldNoWriteBarrier(holder, JSTypedArray::kBasePointerOffset,
407 SmiConstant(0));
408
409 base = RawPtrAdd(base, Signed(offset));
410 StoreObjectFieldNoWriteBarrier<RawPtrT>(
411 holder, JSTypedArray::kExternalPointerOffset, base);
412 }
413
StoreJSTypedArrayElementFromNumeric(TNode<Context> context,TNode<JSTypedArray> typed_array,TNode<UintPtrT> index,TNode<Numeric> value,ElementsKind elements_kind)414 void TypedArrayBuiltinsAssembler::StoreJSTypedArrayElementFromNumeric(
415 TNode<Context> context, TNode<JSTypedArray> typed_array,
416 TNode<UintPtrT> index, TNode<Numeric> value, ElementsKind elements_kind) {
417 TNode<RawPtrT> data_ptr = LoadJSTypedArrayDataPtr(typed_array);
418 switch (elements_kind) {
419 case UINT8_ELEMENTS:
420 case UINT8_CLAMPED_ELEMENTS:
421 case INT8_ELEMENTS:
422 case UINT16_ELEMENTS:
423 case INT16_ELEMENTS:
424 StoreElement(data_ptr, elements_kind, index, SmiToInt32(CAST(value)));
425 break;
426 case UINT32_ELEMENTS:
427 case INT32_ELEMENTS:
428 StoreElement(data_ptr, elements_kind, index,
429 TruncateTaggedToWord32(context, value));
430 break;
431 case FLOAT32_ELEMENTS:
432 StoreElement(data_ptr, elements_kind, index,
433 TruncateFloat64ToFloat32(LoadHeapNumberValue(CAST(value))));
434 break;
435 case FLOAT64_ELEMENTS:
436 StoreElement(data_ptr, elements_kind, index,
437 LoadHeapNumberValue(CAST(value)));
438 break;
439 case BIGUINT64_ELEMENTS:
440 case BIGINT64_ELEMENTS:
441 StoreElement(data_ptr, elements_kind, index,
442 UncheckedCast<BigInt>(value));
443 break;
444 default:
445 UNREACHABLE();
446 }
447 }
448
StoreJSTypedArrayElementFromTagged(TNode<Context> context,TNode<JSTypedArray> typed_array,TNode<UintPtrT> index,TNode<Object> value,ElementsKind elements_kind,Label * if_detached)449 void TypedArrayBuiltinsAssembler::StoreJSTypedArrayElementFromTagged(
450 TNode<Context> context, TNode<JSTypedArray> typed_array,
451 TNode<UintPtrT> index, TNode<Object> value, ElementsKind elements_kind,
452 Label* if_detached) {
453 // |prepared_value| is Word32T or Float64T or Float32T or BigInt.
454 Node* prepared_value =
455 PrepareValueForWriteToTypedArray(value, elements_kind, context);
456
457 // ToNumber/ToBigInt may execute JavaScript code, which could detach
458 // the array's buffer.
459 TNode<JSArrayBuffer> buffer = LoadJSArrayBufferViewBuffer(typed_array);
460 GotoIf(IsDetachedBuffer(buffer), if_detached);
461
462 TNode<RawPtrT> data_ptr = LoadJSTypedArrayDataPtr(typed_array);
463 StoreElement(data_ptr, elements_kind, index, prepared_value);
464 }
465
466 // ES #sec-get-%typedarray%.prototype-@@tostringtag
TF_BUILTIN(TypedArrayPrototypeToStringTag,TypedArrayBuiltinsAssembler)467 TF_BUILTIN(TypedArrayPrototypeToStringTag, TypedArrayBuiltinsAssembler) {
468 TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
469 Label if_receiverisheapobject(this), return_undefined(this);
470 Branch(TaggedIsSmi(receiver), &return_undefined, &if_receiverisheapobject);
471
472 // Dispatch on the elements kind, offset by
473 // FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND.
474 size_t const kTypedElementsKindCount = LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND -
475 FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND +
476 1;
477 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) \
478 Label return_##type##array(this); \
479 BIND(&return_##type##array); \
480 Return(StringConstant(#Type "Array"));
481 TYPED_ARRAYS(TYPED_ARRAY_CASE)
482 #undef TYPED_ARRAY_CASE
483 Label* elements_kind_labels[kTypedElementsKindCount] = {
484 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) &return_##type##array,
485 TYPED_ARRAYS(TYPED_ARRAY_CASE)
486 #undef TYPED_ARRAY_CASE
487 };
488 int32_t elements_kinds[kTypedElementsKindCount] = {
489 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) \
490 TYPE##_ELEMENTS - FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND,
491 TYPED_ARRAYS(TYPED_ARRAY_CASE)
492 #undef TYPED_ARRAY_CASE
493 };
494
495 // We offset the dispatch by FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND, so that
496 // this can be turned into a non-sparse table switch for ideal performance.
497 BIND(&if_receiverisheapobject);
498 TNode<HeapObject> receiver_heap_object = CAST(receiver);
499 TNode<Int32T> elements_kind =
500 Int32Sub(LoadElementsKind(receiver_heap_object),
501 Int32Constant(FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND));
502 Switch(elements_kind, &return_undefined, elements_kinds, elements_kind_labels,
503 kTypedElementsKindCount);
504
505 BIND(&return_undefined);
506 Return(UndefinedConstant());
507 }
508
GenerateTypedArrayPrototypeIterationMethod(TNode<Context> context,TNode<Object> receiver,const char * method_name,IterationKind kind)509 void TypedArrayBuiltinsAssembler::GenerateTypedArrayPrototypeIterationMethod(
510 TNode<Context> context, TNode<Object> receiver, const char* method_name,
511 IterationKind kind) {
512 Label throw_bad_receiver(this, Label::kDeferred);
513
514 GotoIf(TaggedIsSmi(receiver), &throw_bad_receiver);
515 GotoIfNot(IsJSTypedArray(CAST(receiver)), &throw_bad_receiver);
516
517 // Check if the {receiver}'s JSArrayBuffer was detached.
518 ThrowIfArrayBufferViewBufferIsDetached(context, CAST(receiver), method_name);
519
520 Return(CreateArrayIterator(context, receiver, kind));
521
522 BIND(&throw_bad_receiver);
523 ThrowTypeError(context, MessageTemplate::kNotTypedArray, method_name);
524 }
525
526 // ES #sec-%typedarray%.prototype.values
TF_BUILTIN(TypedArrayPrototypeValues,TypedArrayBuiltinsAssembler)527 TF_BUILTIN(TypedArrayPrototypeValues, TypedArrayBuiltinsAssembler) {
528 TNode<Context> context = CAST(Parameter(Descriptor::kContext));
529 TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
530 GenerateTypedArrayPrototypeIterationMethod(context, receiver,
531 "%TypedArray%.prototype.values()",
532 IterationKind::kValues);
533 }
534
535 // ES #sec-%typedarray%.prototype.entries
TF_BUILTIN(TypedArrayPrototypeEntries,TypedArrayBuiltinsAssembler)536 TF_BUILTIN(TypedArrayPrototypeEntries, TypedArrayBuiltinsAssembler) {
537 TNode<Context> context = CAST(Parameter(Descriptor::kContext));
538 TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
539 GenerateTypedArrayPrototypeIterationMethod(context, receiver,
540 "%TypedArray%.prototype.entries()",
541 IterationKind::kEntries);
542 }
543
544 // ES #sec-%typedarray%.prototype.keys
TF_BUILTIN(TypedArrayPrototypeKeys,TypedArrayBuiltinsAssembler)545 TF_BUILTIN(TypedArrayPrototypeKeys, TypedArrayBuiltinsAssembler) {
546 TNode<Context> context = CAST(Parameter(Descriptor::kContext));
547 TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
548 GenerateTypedArrayPrototypeIterationMethod(
549 context, receiver, "%TypedArray%.prototype.keys()", IterationKind::kKeys);
550 }
551
552 } // namespace internal
553 } // namespace v8
554