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::StoreObjectElement(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 // Check if buffer has been neutered. | |
4739 Node* buffer = LoadObjectField(object, JSArrayBufferView::kBufferOffset); | |
4740 Node* bitfield = LoadObjectField(buffer, JSArrayBuffer::kBitFieldOffset, | |
4741 MachineType::Uint32()); | |
4742 Node* neutered_bit = | |
4743 Word32And(bitfield, Int32Constant(JSArrayBuffer::WasNeutered::kMask)); | |
4744 GotoUnless(Word32Equal(neutered_bit, Int32Constant(0)), bailout); | |
4745 | |
4746 // Bounds check. | |
4747 Node* length = UntagParameter( | |
4748 LoadObjectField(object, JSTypedArray::kLengthOffset), parameter_mode); | |
4749 | |
4750 if (store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) { | |
4751 // Skip the store if we write beyond the length. | |
4752 GotoUnless(IntPtrLessThan(key, length), &done); | |
4753 // ... but bailout if the key is negative. | |
4754 } else { | |
4755 DCHECK_EQ(STANDARD_STORE, store_mode); | |
4756 } | |
4757 GotoUnless(UintPtrLessThan(key, length), bailout); | |
4758 | |
4759 // Backing store = external_pointer + base_pointer. | |
4760 // NOTE: there must be no allocations between the backing store calculation | |
4761 // and the actual store, because GC may move the elements. | |
4762 Node* external_pointer = | |
4763 LoadObjectField(elements, FixedTypedArrayBase::kExternalPointerOffset, | |
4764 MachineType::Pointer()); | |
4765 Node* base_pointer = | |
4766 LoadObjectField(elements, FixedTypedArrayBase::kBasePointerOffset); | |
4767 Node* backing_store = IntPtrAdd(external_pointer, base_pointer); | |
4768 StoreElement(backing_store, elements_kind, key, value, parameter_mode); | |
Benedikt Meurer
2016/09/13 11:02:57
Can we Retain the buffer for safety reasons for no
Igor Sheludko
2016/09/14 07:24:08
Done.
| |
4769 Goto(&done); | |
4770 | |
4771 Bind(&done); | |
4772 return; | |
4773 } | |
4774 DCHECK(IsFastSmiOrObjectElementsKind(elements_kind) || | |
4775 IsFastDoubleElementsKind(elements_kind)); | |
4776 | |
4777 Node* length = is_jsarray ? LoadObjectField(object, JSArray::kLengthOffset) | |
4778 : LoadFixedArrayBaseLength(elements); | |
4779 length = UntagParameter(length, parameter_mode); | |
4780 | |
4781 // In case value is stored into a fast smi array, assure that the value is | |
4782 // a smi before manipulating the backing store. Otherwise the backing store | |
4783 // may be left in an invalid state. | |
4784 if (IsFastSmiElementsKind(elements_kind)) { | |
4785 GotoUnless(WordIsSmi(value), bailout); | |
4786 } else if (IsFastDoubleElementsKind(elements_kind)) { | |
4787 value = PrepareValueForWrite(value, Representation::Double(), bailout); | |
4788 } | |
4789 | |
4790 if (IsGrowStoreMode(store_mode)) { | |
4791 elements = CheckForCapacityGrow(object, elements, elements_kind, length, | |
4792 key, parameter_mode, is_jsarray, bailout); | |
4793 } else { | |
4794 GotoUnless(UintPtrLessThan(key, length), bailout); | |
4795 | |
4796 if ((store_mode == STORE_NO_TRANSITION_HANDLE_COW) && | |
4797 IsFastSmiOrObjectElementsKind(elements_kind)) { | |
4798 elements = CopyElementsOnWrite(object, elements, elements_kind, length, | |
4799 parameter_mode, bailout); | |
4800 } | |
4801 } | |
4802 StoreElement(elements, elements_kind, key, value, parameter_mode); | |
4803 } | |
4804 | |
4805 Node* CodeStubAssembler::CheckForCapacityGrow(Node* object, Node* elements, | |
4806 ElementsKind kind, Node* length, | |
4807 Node* key, ParameterMode mode, | |
4808 bool is_js_array, | |
4809 Label* bailout) { | |
4810 Variable checked_elements(this, MachineRepresentation::kTagged); | |
4811 Label grow_case(this), no_grow_case(this), done(this); | |
4812 | |
4813 Node* condition; | |
4814 if (IsHoleyElementsKind(kind)) { | |
4815 condition = UintPtrGreaterThanOrEqual(key, length); | |
4816 } else { | |
4817 condition = WordEqual(key, length); | |
4818 } | |
4819 Branch(condition, &grow_case, &no_grow_case); | |
4820 | |
4821 Bind(&grow_case); | |
4822 { | |
4823 Node* current_capacity = | |
4824 UntagParameter(LoadFixedArrayBaseLength(elements), mode); | |
4825 | |
4826 checked_elements.Bind(elements); | |
4827 | |
4828 Label fits_capacity(this); | |
4829 GotoIf(UintPtrLessThan(key, current_capacity), &fits_capacity); | |
4830 { | |
4831 Node* new_elements = TryGrowElementsCapacity( | |
4832 object, elements, kind, key, current_capacity, mode, bailout); | |
4833 | |
4834 checked_elements.Bind(new_elements); | |
4835 Goto(&fits_capacity); | |
4836 } | |
4837 Bind(&fits_capacity); | |
4838 | |
4839 if (is_js_array) { | |
4840 Node* new_length = IntPtrAdd(key, IntPtrOrSmiConstant(1, mode)); | |
4841 StoreObjectFieldNoWriteBarrier(object, JSArray::kLengthOffset, | |
4842 TagParameter(new_length, mode)); | |
4843 } | |
4844 Goto(&done); | |
4845 } | |
4846 | |
4847 Bind(&no_grow_case); | |
4848 { | |
4849 GotoUnless(UintPtrLessThan(key, length), bailout); | |
4850 checked_elements.Bind(elements); | |
4851 Goto(&done); | |
4852 } | |
4853 | |
4854 Bind(&done); | |
4855 return checked_elements.value(); | |
4856 } | |
4857 | |
4858 Node* CodeStubAssembler::CopyElementsOnWrite(Node* object, Node* elements, | |
4859 ElementsKind kind, Node* length, | |
4860 ParameterMode mode, | |
4861 Label* bailout) { | |
4862 Variable new_elements_var(this, MachineRepresentation::kTagged); | |
4863 Label done(this); | |
4864 | |
4865 new_elements_var.Bind(elements); | |
4866 GotoUnless( | |
4867 WordEqual(LoadMap(elements), LoadRoot(Heap::kFixedCOWArrayMapRootIndex)), | |
4868 &done); | |
4869 { | |
4870 Node* capacity = UntagParameter(LoadFixedArrayBaseLength(elements), mode); | |
4871 Node* new_elements = GrowElementsCapacity(object, elements, kind, kind, | |
4872 length, capacity, mode, bailout); | |
4873 | |
4874 new_elements_var.Bind(new_elements); | |
4875 Goto(&done); | |
4876 } | |
4877 | |
4878 Bind(&done); | |
4879 return new_elements_var.value(); | |
4880 } | |
4881 | |
4640 Node* CodeStubAssembler::EnumLength(Node* map) { | 4882 Node* CodeStubAssembler::EnumLength(Node* map) { |
4641 Node* bitfield_3 = LoadMapBitField3(map); | 4883 Node* bitfield_3 = LoadMapBitField3(map); |
4642 Node* enum_length = BitFieldDecode<Map::EnumLengthBits>(bitfield_3); | 4884 Node* enum_length = BitFieldDecode<Map::EnumLengthBits>(bitfield_3); |
4643 return SmiTag(enum_length); | 4885 return SmiTag(enum_length); |
4644 } | 4886 } |
4645 | 4887 |
4646 void CodeStubAssembler::CheckEnumCache(Node* receiver, Label* use_cache, | 4888 void CodeStubAssembler::CheckEnumCache(Node* receiver, Label* use_cache, |
4647 Label* use_runtime) { | 4889 Label* use_runtime) { |
4648 Variable current_js_object(this, MachineRepresentation::kTagged); | 4890 Variable current_js_object(this, MachineRepresentation::kTagged); |
4649 current_js_object.Bind(receiver); | 4891 current_js_object.Bind(receiver); |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4717 Heap::kTheHoleValueRootIndex); | 4959 Heap::kTheHoleValueRootIndex); |
4718 | 4960 |
4719 // Store the WeakCell in the feedback vector. | 4961 // Store the WeakCell in the feedback vector. |
4720 StoreFixedArrayElement(feedback_vector, slot, cell, UPDATE_WRITE_BARRIER, | 4962 StoreFixedArrayElement(feedback_vector, slot, cell, UPDATE_WRITE_BARRIER, |
4721 CodeStubAssembler::SMI_PARAMETERS); | 4963 CodeStubAssembler::SMI_PARAMETERS); |
4722 return cell; | 4964 return cell; |
4723 } | 4965 } |
4724 | 4966 |
4725 } // namespace internal | 4967 } // namespace internal |
4726 } // namespace v8 | 4968 } // namespace v8 |
OLD | NEW |