OLD | NEW |
1 // Copyright 2016 the V8 project authors. All rights reserved. | 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 | 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/code-stub-assembler.h" | 5 #include "src/code-stub-assembler.h" |
6 #include "src/code-factory.h" | 6 #include "src/code-factory.h" |
7 #include "src/frames-inl.h" | 7 #include "src/frames-inl.h" |
8 #include "src/frames.h" | 8 #include "src/frames.h" |
9 #include "src/ic/handler-configuration.h" | 9 #include "src/ic/handler-configuration.h" |
10 #include "src/ic/stub-cache.h" | 10 #include "src/ic/stub-cache.h" |
(...skipping 3517 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3528 Goto(&return_result); | 3528 Goto(&return_result); |
3529 | 3529 |
3530 Bind(&return_result); | 3530 Bind(&return_result); |
3531 return var_result.value(); | 3531 return var_result.value(); |
3532 } | 3532 } |
3533 | 3533 |
3534 compiler::Node* CodeStubAssembler::ElementOffsetFromIndex(Node* index_node, | 3534 compiler::Node* CodeStubAssembler::ElementOffsetFromIndex(Node* index_node, |
3535 ElementsKind kind, | 3535 ElementsKind kind, |
3536 ParameterMode mode, | 3536 ParameterMode mode, |
3537 int base_size) { | 3537 int base_size) { |
3538 bool is_double = IsFastDoubleElementsKind(kind); | 3538 int element_size_shift = ElementsKindToShiftSize(kind); |
3539 int element_size_shift = is_double ? kDoubleSizeLog2 : kPointerSizeLog2; | |
3540 int element_size = 1 << element_size_shift; | 3539 int element_size = 1 << element_size_shift; |
3541 int const kSmiShiftBits = kSmiShiftSize + kSmiTagSize; | 3540 int const kSmiShiftBits = kSmiShiftSize + kSmiTagSize; |
3542 intptr_t index = 0; | 3541 intptr_t index = 0; |
3543 bool constant_index = false; | 3542 bool constant_index = false; |
3544 if (mode == SMI_PARAMETERS) { | 3543 if (mode == SMI_PARAMETERS) { |
3545 element_size_shift -= kSmiShiftBits; | 3544 element_size_shift -= kSmiShiftBits; |
3546 constant_index = ToIntPtrConstant(index_node, index); | 3545 constant_index = ToIntPtrConstant(index_node, index); |
3547 index = index >> kSmiShiftBits; | 3546 index = index >> kSmiShiftBits; |
3548 } else if (mode == INTEGER_PARAMETERS) { | 3547 } else if (mode == INTEGER_PARAMETERS) { |
3549 int32_t temp = 0; | 3548 int32_t temp = 0; |
(...skipping 1080 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4630 Node* native_context = LoadNativeContext(context); | 4629 Node* native_context = LoadNativeContext(context); |
4631 Node* script_context_table = | 4630 Node* script_context_table = |
4632 LoadContextElement(native_context, Context::SCRIPT_CONTEXT_TABLE_INDEX); | 4631 LoadContextElement(native_context, Context::SCRIPT_CONTEXT_TABLE_INDEX); |
4633 | 4632 |
4634 int offset = | 4633 int offset = |
4635 ScriptContextTable::GetContextOffset(context_index) - kHeapObjectTag; | 4634 ScriptContextTable::GetContextOffset(context_index) - kHeapObjectTag; |
4636 return Load(MachineType::AnyTagged(), script_context_table, | 4635 return Load(MachineType::AnyTagged(), script_context_table, |
4637 IntPtrConstant(offset)); | 4636 IntPtrConstant(offset)); |
4638 } | 4637 } |
4639 | 4638 |
| 4639 Node* CodeStubAssembler::ClampedToUint8(Node* int32_value) { |
| 4640 Label done(this); |
| 4641 Node* int32_zero = Int32Constant(0); |
| 4642 Node* int32_255 = Int32Constant(255); |
| 4643 Variable var_value(this, MachineRepresentation::kWord32); |
| 4644 var_value.Bind(int32_value); |
| 4645 GotoIf(Uint32LessThanOrEqual(int32_value, int32_255), &done); |
| 4646 var_value.Bind(int32_zero); |
| 4647 GotoIf(Int32LessThan(int32_value, int32_zero), &done); |
| 4648 var_value.Bind(int32_255); |
| 4649 Goto(&done); |
| 4650 Bind(&done); |
| 4651 return var_value.value(); |
| 4652 } |
| 4653 |
| 4654 namespace { |
| 4655 |
| 4656 // Converts typed array elements kind to a machine representations. |
| 4657 MachineRepresentation ElementsKindToMachineRepresentation(ElementsKind kind) { |
| 4658 switch (kind) { |
| 4659 case UINT8_CLAMPED_ELEMENTS: |
| 4660 case UINT8_ELEMENTS: |
| 4661 case INT8_ELEMENTS: |
| 4662 return MachineRepresentation::kWord8; |
| 4663 case UINT16_ELEMENTS: |
| 4664 case INT16_ELEMENTS: |
| 4665 return MachineRepresentation::kWord16; |
| 4666 case UINT32_ELEMENTS: |
| 4667 case INT32_ELEMENTS: |
| 4668 return MachineRepresentation::kWord32; |
| 4669 case FLOAT32_ELEMENTS: |
| 4670 return MachineRepresentation::kFloat32; |
| 4671 case FLOAT64_ELEMENTS: |
| 4672 return MachineRepresentation::kFloat64; |
| 4673 default: |
| 4674 UNREACHABLE(); |
| 4675 return MachineRepresentation::kNone; |
| 4676 } |
| 4677 } |
| 4678 |
| 4679 } // namespace |
| 4680 |
| 4681 void CodeStubAssembler::StoreElement(Node* elements, ElementsKind kind, |
| 4682 Node* index, Node* value, |
| 4683 ParameterMode mode) { |
| 4684 if (IsFixedTypedArrayElementsKind(kind)) { |
| 4685 if (kind == UINT8_CLAMPED_ELEMENTS) { |
| 4686 value = ClampedToUint8(value); |
| 4687 } |
| 4688 Node* offset = ElementOffsetFromIndex(index, kind, mode, 0); |
| 4689 MachineRepresentation rep = ElementsKindToMachineRepresentation(kind); |
| 4690 StoreNoWriteBarrier(rep, elements, offset, value); |
| 4691 return; |
| 4692 } |
| 4693 |
| 4694 WriteBarrierMode barrier_mode = |
| 4695 IsFastSmiElementsKind(kind) ? SKIP_WRITE_BARRIER : UPDATE_WRITE_BARRIER; |
| 4696 if (IsFastDoubleElementsKind(kind)) { |
| 4697 // Make sure we do not store signalling NaNs into double arrays. |
| 4698 value = Float64SilenceNaN(value); |
| 4699 StoreFixedDoubleArrayElement(elements, index, value, mode); |
| 4700 } else { |
| 4701 StoreFixedArrayElement(elements, index, value, barrier_mode, mode); |
| 4702 } |
| 4703 } |
| 4704 |
| 4705 void CodeStubAssembler::EmitElementStore(Node* object, Node* key, Node* value, |
| 4706 bool is_jsarray, |
| 4707 ElementsKind elements_kind, |
| 4708 KeyedAccessStoreMode store_mode, |
| 4709 Label* bailout) { |
| 4710 Node* elements = LoadElements(object); |
| 4711 if (IsFastSmiOrObjectElementsKind(elements_kind) && |
| 4712 store_mode != STORE_NO_TRANSITION_HANDLE_COW) { |
| 4713 // Bailout in case of COW elements. |
| 4714 GotoIf(WordNotEqual(LoadMap(elements), |
| 4715 LoadRoot(Heap::kFixedArrayMapRootIndex)), |
| 4716 bailout); |
| 4717 } |
| 4718 // TODO(ishell): introduce TryToIntPtrOrSmi() and use OptimalParameterMode(). |
| 4719 ParameterMode parameter_mode = INTPTR_PARAMETERS; |
| 4720 key = TryToIntptr(key, bailout); |
| 4721 |
| 4722 if (IsFixedTypedArrayElementsKind(elements_kind)) { |
| 4723 Label done(this); |
| 4724 // TODO(ishell): call ToNumber() on value and don't bailout but be careful |
| 4725 // to call it only once if we decide to bailout because of bounds checks. |
| 4726 |
| 4727 if (IsFixedFloatElementsKind(elements_kind)) { |
| 4728 // TODO(ishell): move float32 truncation into PrepareValueForWrite. |
| 4729 value = PrepareValueForWrite(value, Representation::Double(), bailout); |
| 4730 if (elements_kind == FLOAT32_ELEMENTS) { |
| 4731 value = TruncateFloat64ToFloat32(value); |
| 4732 } |
| 4733 } else { |
| 4734 // TODO(ishell): It's fine for word8/16/32 to truncate the result. |
| 4735 value = TryToIntptr(value, bailout); |
| 4736 } |
| 4737 |
| 4738 // There must be no allocations between the buffer load and |
| 4739 // and the actual store to backing store, because GC may decide that |
| 4740 // the buffer is not alive or move the elements. |
| 4741 // TODO(ishell): introduce DisallowHeapAllocationCode scope here. |
| 4742 |
| 4743 // Check if buffer has been neutered. |
| 4744 Node* buffer = LoadObjectField(object, JSArrayBufferView::kBufferOffset); |
| 4745 Node* bitfield = LoadObjectField(buffer, JSArrayBuffer::kBitFieldOffset, |
| 4746 MachineType::Uint32()); |
| 4747 Node* neutered_bit = |
| 4748 Word32And(bitfield, Int32Constant(JSArrayBuffer::WasNeutered::kMask)); |
| 4749 GotoUnless(Word32Equal(neutered_bit, Int32Constant(0)), bailout); |
| 4750 |
| 4751 // Bounds check. |
| 4752 Node* length = UntagParameter( |
| 4753 LoadObjectField(object, JSTypedArray::kLengthOffset), parameter_mode); |
| 4754 |
| 4755 if (store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) { |
| 4756 // Skip the store if we write beyond the length. |
| 4757 GotoUnless(IntPtrLessThan(key, length), &done); |
| 4758 // ... but bailout if the key is negative. |
| 4759 } else { |
| 4760 DCHECK_EQ(STANDARD_STORE, store_mode); |
| 4761 } |
| 4762 GotoUnless(UintPtrLessThan(key, length), bailout); |
| 4763 |
| 4764 // Backing store = external_pointer + base_pointer. |
| 4765 Node* external_pointer = |
| 4766 LoadObjectField(elements, FixedTypedArrayBase::kExternalPointerOffset, |
| 4767 MachineType::Pointer()); |
| 4768 Node* base_pointer = |
| 4769 LoadObjectField(elements, FixedTypedArrayBase::kBasePointerOffset); |
| 4770 Node* backing_store = IntPtrAdd(external_pointer, base_pointer); |
| 4771 StoreElement(backing_store, elements_kind, key, value, parameter_mode); |
| 4772 Goto(&done); |
| 4773 |
| 4774 Bind(&done); |
| 4775 return; |
| 4776 } |
| 4777 DCHECK(IsFastSmiOrObjectElementsKind(elements_kind) || |
| 4778 IsFastDoubleElementsKind(elements_kind)); |
| 4779 |
| 4780 Node* length = is_jsarray ? LoadObjectField(object, JSArray::kLengthOffset) |
| 4781 : LoadFixedArrayBaseLength(elements); |
| 4782 length = UntagParameter(length, parameter_mode); |
| 4783 |
| 4784 // In case value is stored into a fast smi array, assure that the value is |
| 4785 // a smi before manipulating the backing store. Otherwise the backing store |
| 4786 // may be left in an invalid state. |
| 4787 if (IsFastSmiElementsKind(elements_kind)) { |
| 4788 GotoUnless(WordIsSmi(value), bailout); |
| 4789 } else if (IsFastDoubleElementsKind(elements_kind)) { |
| 4790 value = PrepareValueForWrite(value, Representation::Double(), bailout); |
| 4791 } |
| 4792 |
| 4793 if (IsGrowStoreMode(store_mode)) { |
| 4794 elements = CheckForCapacityGrow(object, elements, elements_kind, length, |
| 4795 key, parameter_mode, is_jsarray, bailout); |
| 4796 } else { |
| 4797 GotoUnless(UintPtrLessThan(key, length), bailout); |
| 4798 |
| 4799 if ((store_mode == STORE_NO_TRANSITION_HANDLE_COW) && |
| 4800 IsFastSmiOrObjectElementsKind(elements_kind)) { |
| 4801 elements = CopyElementsOnWrite(object, elements, elements_kind, length, |
| 4802 parameter_mode, bailout); |
| 4803 } |
| 4804 } |
| 4805 StoreElement(elements, elements_kind, key, value, parameter_mode); |
| 4806 } |
| 4807 |
| 4808 Node* CodeStubAssembler::CheckForCapacityGrow(Node* object, Node* elements, |
| 4809 ElementsKind kind, Node* length, |
| 4810 Node* key, ParameterMode mode, |
| 4811 bool is_js_array, |
| 4812 Label* bailout) { |
| 4813 Variable checked_elements(this, MachineRepresentation::kTagged); |
| 4814 Label grow_case(this), no_grow_case(this), done(this); |
| 4815 |
| 4816 Node* condition; |
| 4817 if (IsHoleyElementsKind(kind)) { |
| 4818 condition = UintPtrGreaterThanOrEqual(key, length); |
| 4819 } else { |
| 4820 condition = WordEqual(key, length); |
| 4821 } |
| 4822 Branch(condition, &grow_case, &no_grow_case); |
| 4823 |
| 4824 Bind(&grow_case); |
| 4825 { |
| 4826 Node* current_capacity = |
| 4827 UntagParameter(LoadFixedArrayBaseLength(elements), mode); |
| 4828 |
| 4829 checked_elements.Bind(elements); |
| 4830 |
| 4831 Label fits_capacity(this); |
| 4832 GotoIf(UintPtrLessThan(key, current_capacity), &fits_capacity); |
| 4833 { |
| 4834 Node* new_elements = TryGrowElementsCapacity( |
| 4835 object, elements, kind, key, current_capacity, mode, bailout); |
| 4836 |
| 4837 checked_elements.Bind(new_elements); |
| 4838 Goto(&fits_capacity); |
| 4839 } |
| 4840 Bind(&fits_capacity); |
| 4841 |
| 4842 if (is_js_array) { |
| 4843 Node* new_length = IntPtrAdd(key, IntPtrOrSmiConstant(1, mode)); |
| 4844 StoreObjectFieldNoWriteBarrier(object, JSArray::kLengthOffset, |
| 4845 TagParameter(new_length, mode)); |
| 4846 } |
| 4847 Goto(&done); |
| 4848 } |
| 4849 |
| 4850 Bind(&no_grow_case); |
| 4851 { |
| 4852 GotoUnless(UintPtrLessThan(key, length), bailout); |
| 4853 checked_elements.Bind(elements); |
| 4854 Goto(&done); |
| 4855 } |
| 4856 |
| 4857 Bind(&done); |
| 4858 return checked_elements.value(); |
| 4859 } |
| 4860 |
| 4861 Node* CodeStubAssembler::CopyElementsOnWrite(Node* object, Node* elements, |
| 4862 ElementsKind kind, Node* length, |
| 4863 ParameterMode mode, |
| 4864 Label* bailout) { |
| 4865 Variable new_elements_var(this, MachineRepresentation::kTagged); |
| 4866 Label done(this); |
| 4867 |
| 4868 new_elements_var.Bind(elements); |
| 4869 GotoUnless( |
| 4870 WordEqual(LoadMap(elements), LoadRoot(Heap::kFixedCOWArrayMapRootIndex)), |
| 4871 &done); |
| 4872 { |
| 4873 Node* capacity = UntagParameter(LoadFixedArrayBaseLength(elements), mode); |
| 4874 Node* new_elements = GrowElementsCapacity(object, elements, kind, kind, |
| 4875 length, capacity, mode, bailout); |
| 4876 |
| 4877 new_elements_var.Bind(new_elements); |
| 4878 Goto(&done); |
| 4879 } |
| 4880 |
| 4881 Bind(&done); |
| 4882 return new_elements_var.value(); |
| 4883 } |
| 4884 |
4640 Node* CodeStubAssembler::EnumLength(Node* map) { | 4885 Node* CodeStubAssembler::EnumLength(Node* map) { |
4641 Node* bitfield_3 = LoadMapBitField3(map); | 4886 Node* bitfield_3 = LoadMapBitField3(map); |
4642 Node* enum_length = BitFieldDecode<Map::EnumLengthBits>(bitfield_3); | 4887 Node* enum_length = BitFieldDecode<Map::EnumLengthBits>(bitfield_3); |
4643 return SmiTag(enum_length); | 4888 return SmiTag(enum_length); |
4644 } | 4889 } |
4645 | 4890 |
4646 void CodeStubAssembler::CheckEnumCache(Node* receiver, Label* use_cache, | 4891 void CodeStubAssembler::CheckEnumCache(Node* receiver, Label* use_cache, |
4647 Label* use_runtime) { | 4892 Label* use_runtime) { |
4648 Variable current_js_object(this, MachineRepresentation::kTagged); | 4893 Variable current_js_object(this, MachineRepresentation::kTagged); |
4649 current_js_object.Bind(receiver); | 4894 current_js_object.Bind(receiver); |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4717 Heap::kTheHoleValueRootIndex); | 4962 Heap::kTheHoleValueRootIndex); |
4718 | 4963 |
4719 // Store the WeakCell in the feedback vector. | 4964 // Store the WeakCell in the feedback vector. |
4720 StoreFixedArrayElement(feedback_vector, slot, cell, UPDATE_WRITE_BARRIER, | 4965 StoreFixedArrayElement(feedback_vector, slot, cell, UPDATE_WRITE_BARRIER, |
4721 CodeStubAssembler::SMI_PARAMETERS); | 4966 CodeStubAssembler::SMI_PARAMETERS); |
4722 return cell; | 4967 return cell; |
4723 } | 4968 } |
4724 | 4969 |
4725 } // namespace internal | 4970 } // namespace internal |
4726 } // namespace v8 | 4971 } // namespace v8 |
OLD | NEW |