Line data Source code
1 : // Copyright 2016 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.h"
6 : #include "src/builtins/builtins.h"
7 : #include "src/counters.h"
8 : #include "src/elements.h"
9 : #include "src/objects-inl.h"
10 :
11 : namespace v8 {
12 : namespace internal {
13 :
14 : // -----------------------------------------------------------------------------
15 : // ES6 section 22.2 TypedArray Objects
16 :
17 : // ES6 section 22.2.3.1 get %TypedArray%.prototype.buffer
18 46062 : BUILTIN(TypedArrayPrototypeBuffer) {
19 : HandleScope scope(isolate);
20 17082 : CHECK_RECEIVER(JSTypedArray, typed_array,
21 : "get %TypedArray%.prototype.buffer");
22 29556 : return *typed_array->GetBuffer();
23 : }
24 :
25 : namespace {
26 :
27 19213 : int64_t CapRelativeIndex(Handle<Object> num, int64_t minimum, int64_t maximum) {
28 : int64_t relative;
29 19213 : if (V8_LIKELY(num->IsSmi())) {
30 18241 : relative = Smi::ToInt(*num);
31 : } else {
32 : DCHECK(num->IsHeapNumber());
33 : double fp = HeapNumber::cast(*num)->value();
34 972 : if (V8_UNLIKELY(!std::isfinite(fp))) {
35 : // +Infinity / -Infinity
36 : DCHECK(!std::isnan(fp));
37 891 : return fp < 0 ? minimum : maximum;
38 : }
39 81 : relative = static_cast<int64_t>(fp);
40 : }
41 43286 : return relative < 0 ? std::max<int64_t>(relative + maximum, minimum)
42 51645 : : std::min<int64_t>(relative, maximum);
43 : }
44 :
45 9450 : MaybeHandle<JSTypedArray> TypedArraySpeciesCreateByLength(
46 : Isolate* isolate, Handle<JSTypedArray> exemplar, const char* method_name,
47 : int64_t length) {
48 : const int argc = 1;
49 : ScopedVector<Handle<Object>> argv(argc);
50 9450 : argv[0] = isolate->factory()->NewNumberFromInt64(length);
51 : return JSTypedArray::SpeciesCreate(isolate, exemplar, argc, argv.start(),
52 18900 : method_name);
53 : }
54 :
55 : } // namespace
56 :
57 8532 : BUILTIN(TypedArrayPrototypeCopyWithin) {
58 : HandleScope scope(isolate);
59 :
60 : Handle<JSTypedArray> array;
61 : const char* method = "%TypedArray%.prototype.copyWithin";
62 5688 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
63 : isolate, array, JSTypedArray::Validate(isolate, args.receiver(), method));
64 :
65 2439 : int64_t len = array->length_value();
66 : int64_t to = 0;
67 : int64_t from = 0;
68 : int64_t final = len;
69 :
70 2439 : if (V8_LIKELY(args.length() > 1)) {
71 : Handle<Object> num;
72 2439 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
73 : isolate, num, Object::ToInteger(isolate, args.at<Object>(1)));
74 2439 : to = CapRelativeIndex(num, 0, len);
75 :
76 2439 : if (args.length() > 2) {
77 2430 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
78 : isolate, num, Object::ToInteger(isolate, args.at<Object>(2)));
79 2430 : from = CapRelativeIndex(num, 0, len);
80 :
81 : Handle<Object> end = args.atOrUndefined(isolate, 3);
82 2430 : if (!end->IsUndefined(isolate)) {
83 810 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, num,
84 : Object::ToInteger(isolate, end));
85 810 : final = CapRelativeIndex(num, 0, len);
86 : }
87 : }
88 : }
89 :
90 4878 : int64_t count = std::min<int64_t>(final - from, len - to);
91 2925 : if (count <= 0) return *array;
92 :
93 : // TypedArray buffer may have been transferred/detached during parameter
94 : // processing above. Return early in this case, to prevent potential UAF error
95 : // TODO(caitp): throw here, as though the full algorithm were performed (the
96 : // throw would have come from ecma262/#sec-integerindexedelementget)
97 : // (see )
98 1953 : if (V8_UNLIKELY(array->WasNeutered())) return *array;
99 :
100 : // Ensure processed indexes are within array bounds
101 : DCHECK_GE(from, 0);
102 : DCHECK_LT(from, len);
103 : DCHECK_GE(to, 0);
104 : DCHECK_LT(to, len);
105 : DCHECK_GE(len - count, 0);
106 :
107 : Handle<FixedTypedArrayBase> elements(
108 : FixedTypedArrayBase::cast(array->elements()));
109 1944 : size_t element_size = array->element_size();
110 1944 : to = to * element_size;
111 1944 : from = from * element_size;
112 1944 : count = count * element_size;
113 :
114 : uint8_t* data = static_cast<uint8_t*>(elements->DataPtr());
115 1944 : std::memmove(data + to, data + from, count);
116 :
117 1944 : return *array;
118 : }
119 :
120 7950 : BUILTIN(TypedArrayPrototypeFill) {
121 : HandleScope scope(isolate);
122 :
123 : Handle<JSTypedArray> array;
124 : const char* method = "%TypedArray%.prototype.fill";
125 5300 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
126 : isolate, array, JSTypedArray::Validate(isolate, args.receiver(), method));
127 :
128 2326 : Handle<Object> obj_value = args.atOrUndefined(isolate, 1);
129 4652 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
130 : isolate, obj_value, Object::ToNumber(obj_value));
131 :
132 2326 : int64_t len = array->length_value();
133 : int64_t start = 0;
134 : int64_t end = len;
135 :
136 2326 : if (args.length() > 2) {
137 : Handle<Object> num = args.atOrUndefined(isolate, 2);
138 1215 : if (!num->IsUndefined(isolate)) {
139 1215 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
140 : isolate, num, Object::ToInteger(isolate, num));
141 1215 : start = CapRelativeIndex(num, 0, len);
142 :
143 : num = args.atOrUndefined(isolate, 3);
144 1215 : if (!num->IsUndefined(isolate)) {
145 810 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
146 : isolate, num, Object::ToInteger(isolate, num));
147 810 : end = CapRelativeIndex(num, 0, len);
148 : }
149 : }
150 : }
151 :
152 2326 : int64_t count = end - start;
153 2731 : if (count <= 0) return *array;
154 :
155 1921 : if (V8_UNLIKELY(array->WasNeutered())) return *array;
156 :
157 : // Ensure processed indexes are within array bounds
158 : DCHECK_GE(start, 0);
159 : DCHECK_LT(start, len);
160 : DCHECK_GE(end, 0);
161 : DCHECK_LE(end, len);
162 : DCHECK_LE(count, len);
163 :
164 1921 : return array->GetElementsAccessor()->Fill(isolate, array, obj_value,
165 : static_cast<uint32_t>(start),
166 3842 : static_cast<uint32_t>(end));
167 : }
168 :
169 6426 : BUILTIN(TypedArrayPrototypeIncludes) {
170 : HandleScope scope(isolate);
171 :
172 : Handle<JSTypedArray> array;
173 : const char* method = "%TypedArray%.prototype.includes";
174 4284 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
175 : isolate, array, JSTypedArray::Validate(isolate, args.receiver(), method));
176 :
177 2106 : if (args.length() < 2) return isolate->heap()->false_value();
178 :
179 2025 : int64_t len = array->length_value();
180 2025 : if (len == 0) return isolate->heap()->false_value();
181 :
182 : int64_t index = 0;
183 1782 : if (args.length() > 2) {
184 : Handle<Object> num;
185 1377 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
186 : isolate, num, Object::ToInteger(isolate, args.at<Object>(2)));
187 1215 : index = CapRelativeIndex(num, 0, len);
188 : }
189 :
190 : // TODO(cwhan.tunz): throw. See the above comment in CopyWithin.
191 1620 : if (V8_UNLIKELY(array->WasNeutered())) return isolate->heap()->false_value();
192 :
193 1620 : Handle<Object> search_element = args.atOrUndefined(isolate, 1);
194 1620 : ElementsAccessor* elements = array->GetElementsAccessor();
195 : Maybe<bool> result = elements->IncludesValue(isolate, array, search_element,
196 : static_cast<uint32_t>(index),
197 3240 : static_cast<uint32_t>(len));
198 1620 : MAYBE_RETURN(result, isolate->heap()->exception());
199 3240 : return *isolate->factory()->ToBoolean(result.FromJust());
200 : }
201 :
202 3645 : BUILTIN(TypedArrayPrototypeIndexOf) {
203 : HandleScope scope(isolate);
204 :
205 : Handle<JSTypedArray> array;
206 : const char* method = "%TypedArray%.prototype.indexOf";
207 2430 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
208 : isolate, array, JSTypedArray::Validate(isolate, args.receiver(), method));
209 :
210 1053 : int64_t len = array->length_value();
211 1053 : if (len == 0) return Smi::FromInt(-1);
212 :
213 : int64_t index = 0;
214 972 : if (args.length() > 2) {
215 : Handle<Object> num;
216 486 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
217 : isolate, num, Object::ToInteger(isolate, args.at<Object>(2)));
218 486 : index = CapRelativeIndex(num, 0, len);
219 : }
220 :
221 : // TODO(cwhan.tunz): throw. See the above comment in CopyWithin.
222 972 : if (V8_UNLIKELY(array->WasNeutered())) return Smi::FromInt(-1);
223 :
224 972 : Handle<Object> search_element = args.atOrUndefined(isolate, 1);
225 972 : ElementsAccessor* elements = array->GetElementsAccessor();
226 : Maybe<int64_t> result = elements->IndexOfValue(isolate, array, search_element,
227 : static_cast<uint32_t>(index),
228 1944 : static_cast<uint32_t>(len));
229 972 : MAYBE_RETURN(result, isolate->heap()->exception());
230 1944 : return *isolate->factory()->NewNumberFromInt64(result.FromJust());
231 : }
232 :
233 3402 : BUILTIN(TypedArrayPrototypeLastIndexOf) {
234 : HandleScope scope(isolate);
235 :
236 : Handle<JSTypedArray> array;
237 : const char* method = "%TypedArray%.prototype.lastIndexOf";
238 2268 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
239 : isolate, array, JSTypedArray::Validate(isolate, args.receiver(), method));
240 :
241 972 : int64_t len = array->length_value();
242 972 : if (len == 0) return Smi::FromInt(-1);
243 :
244 891 : int64_t index = len - 1;
245 891 : if (args.length() > 2) {
246 : Handle<Object> num;
247 486 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
248 : isolate, num, Object::ToInteger(isolate, args.at<Object>(2)));
249 : // Set a negative value (-1) for returning -1 if num is negative and
250 : // len + num is still negative. Upper bound is len - 1.
251 972 : index = std::min<int64_t>(CapRelativeIndex(num, -1, len), len - 1);
252 : }
253 :
254 891 : if (index < 0) return Smi::FromInt(-1);
255 :
256 : // TODO(cwhan.tunz): throw. See the above comment in CopyWithin.
257 810 : if (V8_UNLIKELY(array->WasNeutered())) return Smi::FromInt(-1);
258 :
259 810 : Handle<Object> search_element = args.atOrUndefined(isolate, 1);
260 810 : ElementsAccessor* elements = array->GetElementsAccessor();
261 : Maybe<int64_t> result = elements->LastIndexOfValue(
262 1620 : isolate, array, search_element, static_cast<uint32_t>(index));
263 810 : MAYBE_RETURN(result, isolate->heap()->exception());
264 1620 : return *isolate->factory()->NewNumberFromInt64(result.FromJust());
265 : }
266 :
267 972 : BUILTIN(TypedArrayPrototypeReverse) {
268 : HandleScope scope(isolate);
269 :
270 : Handle<JSTypedArray> array;
271 : const char* method = "%TypedArray%.prototype.reverse";
272 648 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
273 : isolate, array, JSTypedArray::Validate(isolate, args.receiver(), method));
274 :
275 162 : ElementsAccessor* elements = array->GetElementsAccessor();
276 324 : elements->Reverse(*array);
277 162 : return *array;
278 : }
279 :
280 : namespace {
281 4954 : Object* TypedArrayCopyElements(Handle<JSTypedArray> target,
282 : Handle<JSReceiver> source, uint32_t length,
283 : uint32_t offset) {
284 4954 : ElementsAccessor* accessor = target->GetElementsAccessor();
285 9908 : return accessor->CopyElements(source, target, length, offset);
286 : }
287 :
288 : enum class TypedArraySetResultCodes {
289 : // Set from typed array of the same type.
290 : // This is processed by TypedArraySetFastCases
291 : SAME_TYPE,
292 : // Set from typed array of the different type, overlapping in memory.
293 : OVERLAPPING,
294 : // Set from typed array of the different type, non-overlapping.
295 : NONOVERLAPPING,
296 : // Set from non-typed array.
297 : NON_TYPED_ARRAY
298 : };
299 :
300 332 : MaybeHandle<Object> TypedArraySetFromOverlapping(Isolate* isolate,
301 : Handle<JSTypedArray> target,
302 : Handle<JSTypedArray> source,
303 : uint32_t offset) {
304 : DCHECK_GE(offset, 0);
305 :
306 332 : size_t sourceElementSize = source->element_size();
307 332 : size_t targetElementSize = target->element_size();
308 :
309 332 : uint32_t source_length = source->length_value();
310 332 : if (source_length == 0) return target;
311 :
312 : // Copy left part.
313 :
314 : // First un-mutated byte after the next write
315 323 : uint32_t target_ptr = 0;
316 323 : CHECK(target->byte_offset()->ToUint32(&target_ptr));
317 323 : target_ptr += (offset + 1) * targetElementSize;
318 :
319 : // Next read at sourcePtr. We do not care for memory changing before
320 : // sourcePtr - we have already copied it.
321 323 : uint32_t source_ptr = 0;
322 323 : CHECK(source->byte_offset()->ToUint32(&source_ptr));
323 :
324 323 : ElementsAccessor* source_accessor = source->GetElementsAccessor();
325 323 : ElementsAccessor* target_accessor = target->GetElementsAccessor();
326 :
327 : uint32_t left_index;
328 137 : for (left_index = 0; left_index < source_length && target_ptr <= source_ptr;
329 : left_index++) {
330 274 : Handle<Object> value = source_accessor->Get(source, left_index);
331 411 : target_accessor->Set(target, offset + left_index, *value);
332 :
333 137 : target_ptr += targetElementSize;
334 137 : source_ptr += sourceElementSize;
335 : }
336 :
337 : // Copy right part;
338 : // First unmutated byte before the next write
339 323 : CHECK(target->byte_offset()->ToUint32(&target_ptr));
340 323 : target_ptr += (offset + source_length - 1) * targetElementSize;
341 :
342 : // Next read before sourcePtr. We do not care for memory changing after
343 : // sourcePtr - we have already copied it.
344 323 : CHECK(target->byte_offset()->ToUint32(&source_ptr));
345 323 : source_ptr += source_length * sourceElementSize;
346 :
347 : uint32_t right_index;
348 : DCHECK_GE(source_length, 1);
349 541 : for (right_index = source_length - 1;
350 356 : right_index > left_index && target_ptr >= source_ptr; right_index--) {
351 436 : Handle<Object> value = source_accessor->Get(source, right_index);
352 654 : target_accessor->Set(target, offset + right_index, *value);
353 :
354 218 : target_ptr -= targetElementSize;
355 218 : source_ptr -= sourceElementSize;
356 : }
357 :
358 323 : std::vector<Handle<Object>> temp(right_index + 1 - left_index);
359 :
360 451 : for (uint32_t i = left_index; i <= right_index; i++) {
361 1353 : temp[i - left_index] = source_accessor->Get(source, i);
362 : }
363 :
364 451 : for (uint32_t i = left_index; i <= right_index; i++) {
365 1353 : target_accessor->Set(target, offset + i, *temp[i - left_index]);
366 : }
367 :
368 323 : return target;
369 : }
370 :
371 9645 : MaybeHandle<Smi> TypedArraySetFastCases(Isolate* isolate,
372 : Handle<JSTypedArray> target,
373 : Handle<Object> source_obj,
374 : Handle<Object> offset_obj) {
375 9645 : if (!source_obj->IsJSTypedArray()) {
376 : return MaybeHandle<Smi>(
377 4878 : Smi::FromEnum(TypedArraySetResultCodes::NON_TYPED_ARRAY), isolate);
378 : }
379 :
380 : Handle<JSTypedArray> source = Handle<JSTypedArray>::cast(source_obj);
381 :
382 : size_t offset = 0;
383 4767 : CHECK(TryNumberToSize(*offset_obj, &offset));
384 4767 : size_t target_length = target->length_value();
385 4767 : size_t source_length = source->length_value();
386 4767 : size_t target_byte_length = NumberToSize(target->byte_length());
387 4767 : size_t source_byte_length = NumberToSize(source->byte_length());
388 4767 : if (offset > target_length || offset + source_length > target_length ||
389 : offset + source_length < offset) { // overflow
390 74 : THROW_NEW_ERROR(
391 : isolate, NewRangeError(MessageTemplate::kTypedArraySetSourceTooLarge),
392 : Smi);
393 : }
394 :
395 4730 : size_t target_offset = NumberToSize(target->byte_offset());
396 4730 : size_t source_offset = NumberToSize(source->byte_offset());
397 : uint8_t* target_base =
398 9460 : static_cast<uint8_t*>(target->GetBuffer()->backing_store()) +
399 4730 : target_offset;
400 : uint8_t* source_base =
401 9460 : static_cast<uint8_t*>(source->GetBuffer()->backing_store()) +
402 4730 : source_offset;
403 :
404 : // Typed arrays of the same type: use memmove.
405 9460 : if (target->type() == source->type()) {
406 4122 : memmove(target_base + offset * target->element_size(), source_base,
407 : source_byte_length);
408 : return MaybeHandle<Smi>(Smi::FromEnum(TypedArraySetResultCodes::SAME_TYPE),
409 4122 : isolate);
410 : }
411 :
412 : // Typed arrays of different types over the same backing store
413 962 : if ((source_base <= target_base &&
414 723 : source_base + source_byte_length > target_base) ||
415 263 : (target_base <= source_base &&
416 263 : target_base + target_byte_length > source_base)) {
417 : // We do not support overlapping ArrayBuffers
418 : DCHECK(target->GetBuffer()->backing_store() ==
419 : source->GetBuffer()->backing_store());
420 : return MaybeHandle<Smi>(
421 332 : Smi::FromEnum(TypedArraySetResultCodes::OVERLAPPING), isolate);
422 : } else { // Non-overlapping typed arrays
423 : return MaybeHandle<Smi>(
424 276 : Smi::FromEnum(TypedArraySetResultCodes::NONOVERLAPPING), isolate);
425 : }
426 : }
427 :
428 : } // anonymous namespace
429 :
430 : // 22.2.3.23%TypedArray%.prototype.set ( overloaded [ , offset ] )
431 29181 : BUILTIN(TypedArrayPrototypeSet) {
432 : HandleScope scope(isolate);
433 :
434 : Handle<Object> target = args.receiver();
435 : Handle<Object> obj = args.atOrUndefined(isolate, 1);
436 : Handle<Object> offset = args.atOrUndefined(isolate, 2);
437 : const char* method = "%TypedArray%.prototype.set";
438 :
439 9727 : if (!target->IsJSTypedArray()) {
440 144 : THROW_NEW_ERROR_RETURN_FAILURE(
441 : isolate, NewTypeError(MessageTemplate::kNotTypedArray));
442 : }
443 :
444 9655 : if (offset->IsUndefined(isolate)) {
445 : offset = Handle<Object>(Smi::kZero, isolate);
446 : } else {
447 7827 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, offset,
448 : Object::ToInteger(isolate, offset));
449 : }
450 :
451 9655 : if (offset->Number() < 0) {
452 0 : THROW_NEW_ERROR_RETURN_FAILURE(
453 : isolate, NewRangeError(MessageTemplate::kTypedArraySetNegativeOffset));
454 : }
455 :
456 9655 : if (offset->Number() > Smi::kMaxValue) {
457 20 : THROW_NEW_ERROR_RETURN_FAILURE(
458 : isolate, NewRangeError(MessageTemplate::kTypedArraySetSourceTooLarge));
459 : }
460 :
461 : Handle<JSTypedArray> target_array = Handle<JSTypedArray>::cast(target);
462 9645 : if (V8_UNLIKELY(target_array->WasNeutered())) {
463 : const MessageTemplate::Template message =
464 : MessageTemplate::kDetachedOperation;
465 : Handle<String> operation =
466 0 : isolate->factory()->NewStringFromAsciiChecked(method);
467 0 : THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewTypeError(message, operation));
468 : }
469 :
470 : uint32_t uint_offset;
471 9645 : CHECK(offset->ToUint32(&uint_offset));
472 :
473 : // TODO(cwhan.tunz): Implement CopyElements for overlapping cases, and use
474 : // TypedArrayCopyElements for all case instead of this result code based
475 : // branches
476 : Handle<Smi> result_code;
477 19290 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
478 : isolate, result_code,
479 : TypedArraySetFastCases(isolate, target_array, obj, offset));
480 :
481 9608 : switch (static_cast<TypedArraySetResultCodes>(result_code->value())) {
482 : case TypedArraySetResultCodes::SAME_TYPE: {
483 : break;
484 : }
485 : case TypedArraySetResultCodes::OVERLAPPING: {
486 664 : RETURN_FAILURE_ON_EXCEPTION(
487 : isolate, TypedArraySetFromOverlapping(isolate, target_array,
488 : Handle<JSTypedArray>::cast(obj),
489 : uint_offset));
490 : break;
491 : }
492 : case TypedArraySetResultCodes::NONOVERLAPPING: {
493 : return TypedArrayCopyElements(
494 : target_array, Handle<JSTypedArray>::cast(obj),
495 828 : Handle<JSTypedArray>::cast(obj)->length_value(), uint_offset);
496 : break;
497 : }
498 : case TypedArraySetResultCodes::NON_TYPED_ARRAY: {
499 4878 : if (obj->IsNumber()) {
500 : // For number as a first argument, throw TypeError
501 : // instead of silently ignoring the call, so that
502 : // users know they did something wrong.
503 : // (Consistent with Firefox and Blink/WebKit)
504 128 : THROW_NEW_ERROR_RETURN_FAILURE(
505 : isolate, NewTypeError(MessageTemplate::kInvalidArgument));
506 : }
507 :
508 9628 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, obj,
509 : Object::ToObject(isolate, obj));
510 :
511 : Handle<Object> len;
512 9628 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
513 : isolate, len,
514 : Object::GetProperty(obj, isolate->factory()->length_string()));
515 4814 : if (len->IsUndefined(isolate)) {
516 : break;
517 : }
518 9554 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, len,
519 : Object::ToLength(isolate, len));
520 :
521 : DCHECK_GE(uint_offset, 0);
522 14088 : if (uint_offset + len->Number() > target_array->length_value()) {
523 36 : THROW_NEW_ERROR_RETURN_FAILURE(
524 : isolate,
525 : NewRangeError(MessageTemplate::kTypedArraySetSourceTooLarge));
526 : }
527 : uint32_t int_l;
528 4678 : CHECK(DoubleToUint32IfEqualToSelf(len->Number(), &int_l));
529 : return TypedArrayCopyElements(target_array, Handle<JSReceiver>::cast(obj),
530 4678 : int_l, uint_offset);
531 : } break;
532 : }
533 :
534 : return *isolate->factory()->undefined_value();
535 : }
536 :
537 28836 : BUILTIN(TypedArrayPrototypeSlice) {
538 : HandleScope scope(isolate);
539 :
540 : Handle<JSTypedArray> array;
541 : const char* method = "%TypedArray%.prototype.slice";
542 19224 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
543 : isolate, array, JSTypedArray::Validate(isolate, args.receiver(), method));
544 :
545 9450 : int64_t len = array->length_value();
546 : int64_t start = 0;
547 : int64_t end = len;
548 : {
549 : Handle<Object> num = args.atOrUndefined(isolate, 1);
550 9450 : if (!num->IsUndefined(isolate)) {
551 5876 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, num,
552 : Object::ToInteger(isolate, num));
553 5876 : start = CapRelativeIndex(num, 0, len);
554 :
555 : num = args.atOrUndefined(isolate, 2);
556 5876 : if (!num->IsUndefined(isolate)) {
557 3446 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, num,
558 : Object::ToInteger(isolate, num));
559 3446 : end = CapRelativeIndex(num, 0, len);
560 : }
561 : }
562 : }
563 :
564 18900 : int64_t count = std::max<int64_t>(end - start, 0);
565 :
566 : Handle<JSTypedArray> result_array;
567 18900 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
568 : isolate, result_array,
569 : TypedArraySpeciesCreateByLength(isolate, array, method, count));
570 :
571 : // TODO(cwhan.tunz): neutering check of the result_array should be done in
572 : // TypedArraySpeciesCreate, but currently ValidateTypedArray does not throw
573 : // for neutered buffer, so this is a temporary neutering check for the result
574 : // array
575 9207 : if (V8_UNLIKELY(result_array->WasNeutered())) return *result_array;
576 :
577 : // TODO(cwhan.tunz): should throw.
578 9207 : if (V8_UNLIKELY(array->WasNeutered())) return *result_array;
579 :
580 9207 : if (count == 0) return *result_array;
581 :
582 6453 : ElementsAccessor* accessor = array->GetElementsAccessor();
583 : return *accessor->Slice(array, static_cast<uint32_t>(start),
584 25812 : static_cast<uint32_t>(end), result_array);
585 : }
586 :
587 : } // namespace internal
588 : } // namespace v8
|