OLD | NEW |
1 // Copyright 2016 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/builtins/builtins-utils.h" | 5 #include "src/builtins/builtins-utils-gen.h" |
6 #include "src/builtins/builtins.h" | 6 #include "src/builtins/builtins.h" |
7 #include "src/code-stub-assembler.h" | 7 #include "src/code-stub-assembler.h" |
8 #include "src/counters.h" | |
9 #include "src/elements.h" | |
10 #include "src/objects-inl.h" | |
11 | 8 |
12 namespace v8 { | 9 namespace v8 { |
13 namespace internal { | 10 namespace internal { |
14 | 11 |
| 12 // ----------------------------------------------------------------------------- |
| 13 // ES6 section 22.2 TypedArray Objects |
| 14 |
15 class TypedArrayBuiltinsAssembler : public CodeStubAssembler { | 15 class TypedArrayBuiltinsAssembler : public CodeStubAssembler { |
16 public: | 16 public: |
17 explicit TypedArrayBuiltinsAssembler(compiler::CodeAssemblerState* state) | 17 explicit TypedArrayBuiltinsAssembler(compiler::CodeAssemblerState* state) |
18 : CodeStubAssembler(state) {} | 18 : CodeStubAssembler(state) {} |
19 | 19 |
20 protected: | 20 protected: |
21 void GenerateTypedArrayPrototypeGetter(const char* method_name, | 21 void GenerateTypedArrayPrototypeGetter(const char* method_name, |
22 int object_offset); | 22 int object_offset); |
23 template <IterationKind kIterationKind> | 23 template <IterationKind kIterationKind> |
24 void GenerateTypedArrayPrototypeIterationMethod(const char* method_name); | 24 void GenerateTypedArrayPrototypeIterationMethod(const char* method_name); |
(...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
285 Node* const maybe_buffer = Parameter(3); | 285 Node* const maybe_buffer = Parameter(3); |
286 Node* const byte_offset = Parameter(4); | 286 Node* const byte_offset = Parameter(4); |
287 Node* byte_length = Parameter(5); | 287 Node* byte_length = Parameter(5); |
288 Node* const initialize = Parameter(6); | 288 Node* const initialize = Parameter(6); |
289 Node* const context = Parameter(9); | 289 Node* const context = Parameter(9); |
290 | 290 |
291 DoInitialize(holder, length, maybe_buffer, byte_offset, byte_length, | 291 DoInitialize(holder, length, maybe_buffer, byte_offset, byte_length, |
292 initialize, context); | 292 initialize, context); |
293 } | 293 } |
294 | 294 |
295 // ----------------------------------------------------------------------------- | |
296 // ES6 section 22.2 TypedArray Objects | |
297 | |
298 // ES6 section 22.2.4.2 TypedArray ( length ) | 295 // ES6 section 22.2.4.2 TypedArray ( length ) |
299 TF_BUILTIN(TypedArrayConstructByLength, TypedArrayBuiltinsAssembler) { | 296 TF_BUILTIN(TypedArrayConstructByLength, TypedArrayBuiltinsAssembler) { |
300 // We know that holder cannot be an object if this builtin was called. | 297 // We know that holder cannot be an object if this builtin was called. |
301 Node* holder = Parameter(1); | 298 Node* holder = Parameter(1); |
302 Node* length = Parameter(2); | 299 Node* length = Parameter(2); |
303 Node* element_size = Parameter(3); | 300 Node* element_size = Parameter(3); |
304 Node* context = Parameter(6); | 301 Node* context = Parameter(6); |
305 | 302 |
306 Variable maybe_buffer(this, MachineRepresentation::kTagged); | 303 Variable maybe_buffer(this, MachineRepresentation::kTagged); |
307 maybe_buffer.Bind(NullConstant()); | 304 maybe_buffer.Bind(NullConstant()); |
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
462 } | 459 } |
463 | 460 |
464 Bind(&invalid_length); | 461 Bind(&invalid_length); |
465 { | 462 { |
466 CallRuntime(Runtime::kThrowRangeError, context, | 463 CallRuntime(Runtime::kThrowRangeError, context, |
467 SmiConstant(MessageTemplate::kInvalidTypedArrayLength)); | 464 SmiConstant(MessageTemplate::kInvalidTypedArrayLength)); |
468 Unreachable(); | 465 Unreachable(); |
469 } | 466 } |
470 } | 467 } |
471 | 468 |
472 // ES6 section 22.2.3.1 get %TypedArray%.prototype.buffer | |
473 BUILTIN(TypedArrayPrototypeBuffer) { | |
474 HandleScope scope(isolate); | |
475 CHECK_RECEIVER(JSTypedArray, typed_array, "get TypedArray.prototype.buffer"); | |
476 return *typed_array->GetBuffer(); | |
477 } | |
478 | |
479 void TypedArrayBuiltinsAssembler::GenerateTypedArrayPrototypeGetter( | 469 void TypedArrayBuiltinsAssembler::GenerateTypedArrayPrototypeGetter( |
480 const char* method_name, int object_offset) { | 470 const char* method_name, int object_offset) { |
481 Node* receiver = Parameter(0); | 471 Node* receiver = Parameter(0); |
482 Node* context = Parameter(3); | 472 Node* context = Parameter(3); |
483 | 473 |
484 // Check if the {receiver} is actually a JSTypedArray. | 474 // Check if the {receiver} is actually a JSTypedArray. |
485 Label receiver_is_incompatible(this, Label::kDeferred); | 475 Label receiver_is_incompatible(this, Label::kDeferred); |
486 GotoIf(TaggedIsSmi(receiver), &receiver_is_incompatible); | 476 GotoIf(TaggedIsSmi(receiver), &receiver_is_incompatible); |
487 GotoIfNot(HasInstanceType(receiver, JS_TYPED_ARRAY_TYPE), | 477 GotoIfNot(HasInstanceType(receiver, JS_TYPED_ARRAY_TYPE), |
488 &receiver_is_incompatible); | 478 &receiver_is_incompatible); |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
582 TF_BUILTIN(TypedArrayPrototypeEntries, TypedArrayBuiltinsAssembler) { | 572 TF_BUILTIN(TypedArrayPrototypeEntries, TypedArrayBuiltinsAssembler) { |
583 GenerateTypedArrayPrototypeIterationMethod<IterationKind::kEntries>( | 573 GenerateTypedArrayPrototypeIterationMethod<IterationKind::kEntries>( |
584 "%TypedArray%.prototype.entries()"); | 574 "%TypedArray%.prototype.entries()"); |
585 } | 575 } |
586 | 576 |
587 TF_BUILTIN(TypedArrayPrototypeKeys, TypedArrayBuiltinsAssembler) { | 577 TF_BUILTIN(TypedArrayPrototypeKeys, TypedArrayBuiltinsAssembler) { |
588 GenerateTypedArrayPrototypeIterationMethod<IterationKind::kKeys>( | 578 GenerateTypedArrayPrototypeIterationMethod<IterationKind::kKeys>( |
589 "%TypedArray%.prototype.keys()"); | 579 "%TypedArray%.prototype.keys()"); |
590 } | 580 } |
591 | 581 |
592 namespace { | |
593 | |
594 int64_t CapRelativeIndex(Handle<Object> num, int64_t minimum, int64_t maximum) { | |
595 int64_t relative; | |
596 if (V8_LIKELY(num->IsSmi())) { | |
597 relative = Smi::cast(*num)->value(); | |
598 } else { | |
599 DCHECK(num->IsHeapNumber()); | |
600 double fp = HeapNumber::cast(*num)->value(); | |
601 if (V8_UNLIKELY(!std::isfinite(fp))) { | |
602 // +Infinity / -Infinity | |
603 DCHECK(!std::isnan(fp)); | |
604 return fp < 0 ? minimum : maximum; | |
605 } | |
606 relative = static_cast<int64_t>(fp); | |
607 } | |
608 return relative < 0 ? std::max<int64_t>(relative + maximum, minimum) | |
609 : std::min<int64_t>(relative, maximum); | |
610 } | |
611 | |
612 } // namespace | |
613 | |
614 BUILTIN(TypedArrayPrototypeCopyWithin) { | |
615 HandleScope scope(isolate); | |
616 | |
617 Handle<JSTypedArray> array; | |
618 const char* method = "%TypedArray%.prototype.copyWithin"; | |
619 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
620 isolate, array, JSTypedArray::Validate(isolate, args.receiver(), method)); | |
621 | |
622 if (V8_UNLIKELY(array->WasNeutered())) return *array; | |
623 | |
624 int64_t len = array->length_value(); | |
625 int64_t to = 0; | |
626 int64_t from = 0; | |
627 int64_t final = len; | |
628 | |
629 if (V8_LIKELY(args.length() > 1)) { | |
630 Handle<Object> num; | |
631 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
632 isolate, num, Object::ToInteger(isolate, args.at<Object>(1))); | |
633 to = CapRelativeIndex(num, 0, len); | |
634 | |
635 if (args.length() > 2) { | |
636 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
637 isolate, num, Object::ToInteger(isolate, args.at<Object>(2))); | |
638 from = CapRelativeIndex(num, 0, len); | |
639 | |
640 Handle<Object> end = args.atOrUndefined(isolate, 3); | |
641 if (!end->IsUndefined(isolate)) { | |
642 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, num, | |
643 Object::ToInteger(isolate, end)); | |
644 final = CapRelativeIndex(num, 0, len); | |
645 } | |
646 } | |
647 } | |
648 | |
649 int64_t count = std::min<int64_t>(final - from, len - to); | |
650 if (count <= 0) return *array; | |
651 | |
652 // TypedArray buffer may have been transferred/detached during parameter | |
653 // processing above. Return early in this case, to prevent potential UAF error | |
654 // TODO(caitp): throw here, as though the full algorithm were performed (the | |
655 // throw would have come from ecma262/#sec-integerindexedelementget) | |
656 // (see ) | |
657 if (V8_UNLIKELY(array->WasNeutered())) return *array; | |
658 | |
659 // Ensure processed indexes are within array bounds | |
660 DCHECK_GE(from, 0); | |
661 DCHECK_LT(from, len); | |
662 DCHECK_GE(to, 0); | |
663 DCHECK_LT(to, len); | |
664 DCHECK_GE(len - count, 0); | |
665 | |
666 Handle<FixedTypedArrayBase> elements( | |
667 FixedTypedArrayBase::cast(array->elements())); | |
668 size_t element_size = array->element_size(); | |
669 to = to * element_size; | |
670 from = from * element_size; | |
671 count = count * element_size; | |
672 | |
673 uint8_t* data = static_cast<uint8_t*>(elements->DataPtr()); | |
674 std::memmove(data + to, data + from, count); | |
675 | |
676 return *array; | |
677 } | |
678 | |
679 BUILTIN(TypedArrayPrototypeIncludes) { | |
680 HandleScope scope(isolate); | |
681 | |
682 Handle<JSTypedArray> array; | |
683 const char* method = "%TypedArray%.prototype.includes"; | |
684 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
685 isolate, array, JSTypedArray::Validate(isolate, args.receiver(), method)); | |
686 | |
687 if (args.length() < 2) return isolate->heap()->false_value(); | |
688 | |
689 int64_t len = array->length_value(); | |
690 if (len == 0) return isolate->heap()->false_value(); | |
691 | |
692 int64_t index = 0; | |
693 if (args.length() > 2) { | |
694 Handle<Object> num; | |
695 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
696 isolate, num, Object::ToInteger(isolate, args.at<Object>(2))); | |
697 index = CapRelativeIndex(num, 0, len); | |
698 } | |
699 | |
700 // TODO(cwhan.tunz): throw. See the above comment in CopyWithin. | |
701 if (V8_UNLIKELY(array->WasNeutered())) return isolate->heap()->false_value(); | |
702 | |
703 Handle<Object> search_element = args.atOrUndefined(isolate, 1); | |
704 ElementsAccessor* elements = array->GetElementsAccessor(); | |
705 Maybe<bool> result = elements->IncludesValue(isolate, array, search_element, | |
706 static_cast<uint32_t>(index), | |
707 static_cast<uint32_t>(len)); | |
708 MAYBE_RETURN(result, isolate->heap()->exception()); | |
709 return *isolate->factory()->ToBoolean(result.FromJust()); | |
710 } | |
711 | |
712 BUILTIN(TypedArrayPrototypeIndexOf) { | |
713 HandleScope scope(isolate); | |
714 | |
715 Handle<JSTypedArray> array; | |
716 const char* method = "%TypedArray%.prototype.indexOf"; | |
717 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
718 isolate, array, JSTypedArray::Validate(isolate, args.receiver(), method)); | |
719 | |
720 int64_t len = array->length_value(); | |
721 if (len == 0) return Smi::FromInt(-1); | |
722 | |
723 int64_t index = 0; | |
724 if (args.length() > 2) { | |
725 Handle<Object> num; | |
726 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
727 isolate, num, Object::ToInteger(isolate, args.at<Object>(2))); | |
728 index = CapRelativeIndex(num, 0, len); | |
729 } | |
730 | |
731 // TODO(cwhan.tunz): throw. See the above comment in CopyWithin. | |
732 if (V8_UNLIKELY(array->WasNeutered())) return Smi::FromInt(-1); | |
733 | |
734 Handle<Object> search_element = args.atOrUndefined(isolate, 1); | |
735 ElementsAccessor* elements = array->GetElementsAccessor(); | |
736 Maybe<int64_t> result = elements->IndexOfValue(isolate, array, search_element, | |
737 static_cast<uint32_t>(index), | |
738 static_cast<uint32_t>(len)); | |
739 MAYBE_RETURN(result, isolate->heap()->exception()); | |
740 return *isolate->factory()->NewNumberFromInt64(result.FromJust()); | |
741 } | |
742 | |
743 } // namespace internal | 582 } // namespace internal |
744 } // namespace v8 | 583 } // namespace v8 |
OLD | NEW |