| 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 |