Index: src/code-stub-assembler.cc |
diff --git a/src/code-stub-assembler.cc b/src/code-stub-assembler.cc |
index d172ad7ab2a1c2d548f893615619fe0e9f39f2bf..c4c90f94b93b241e66b016dd781b502ed678edd9 100644 |
--- a/src/code-stub-assembler.cc |
+++ b/src/code-stub-assembler.cc |
@@ -3354,8 +3354,7 @@ compiler::Node* CodeStubAssembler::ElementOffsetFromIndex(Node* index_node, |
ElementsKind kind, |
ParameterMode mode, |
int base_size) { |
- bool is_double = IsFastDoubleElementsKind(kind); |
- int element_size_shift = is_double ? kDoubleSizeLog2 : kPointerSizeLog2; |
+ int element_size_shift = ElementsKindToShiftSize(kind); |
int element_size = 1 << element_size_shift; |
int const kSmiShiftBits = kSmiShiftSize + kSmiTagSize; |
intptr_t index = 0; |
@@ -4456,6 +4455,243 @@ Node* CodeStubAssembler::LoadScriptContext(Node* context, int context_index) { |
IntPtrConstant(offset)); |
} |
+Node* CodeStubAssembler::ClampedToUint8(Node* int32_value) { |
+ Label done(this); |
+ Node* int32_zero = Int32Constant(0); |
+ Node* int32_255 = Int32Constant(255); |
+ Variable var_value(this, MachineRepresentation::kWord32); |
+ var_value.Bind(int32_value); |
+ GotoIf(Uint32LessThanOrEqual(int32_value, int32_255), &done); |
+ var_value.Bind(int32_zero); |
+ GotoIf(Int32LessThan(int32_value, int32_zero), &done); |
+ var_value.Bind(int32_255); |
+ Goto(&done); |
+ Bind(&done); |
+ return var_value.value(); |
+} |
+ |
+namespace { |
Benedikt Meurer
2016/09/13 09:08:00
Nit: add empty line.
Igor Sheludko
2016/09/13 10:33:16
Done.
|
+// Converts typed array elements kind to a machine representations. |
+MachineRepresentation ElementsKindToMachineRepresentation(ElementsKind kind) { |
+ switch (kind) { |
+ case UINT8_CLAMPED_ELEMENTS: |
+ case UINT8_ELEMENTS: |
+ case INT8_ELEMENTS: |
+ return MachineRepresentation::kWord8; |
+ case UINT16_ELEMENTS: |
+ case INT16_ELEMENTS: |
+ return MachineRepresentation::kWord16; |
+ case UINT32_ELEMENTS: |
+ case INT32_ELEMENTS: |
+ return MachineRepresentation::kWord32; |
+ case FLOAT32_ELEMENTS: |
+ return MachineRepresentation::kFloat32; |
+ case FLOAT64_ELEMENTS: |
+ return MachineRepresentation::kFloat64; |
+ default: |
+ UNREACHABLE(); |
+ return MachineRepresentation::kNone; |
+ } |
+} |
+} // namespace |
Benedikt Meurer
2016/09/13 09:08:00
Nit: add empty line.
Igor Sheludko
2016/09/13 10:33:16
Done.
|
+ |
+void CodeStubAssembler::StoreElement(Node* elements, ElementsKind kind, |
+ Node* index, Node* value, |
+ ParameterMode mode) { |
+ if (IsFixedTypedArrayElementsKind(kind)) { |
+ if (kind == UINT8_CLAMPED_ELEMENTS) { |
+ value = ClampedToUint8(value); |
+ } |
+ Node* offset = ElementOffsetFromIndex(index, kind, mode, 0); |
+ MachineRepresentation rep = ElementsKindToMachineRepresentation(kind); |
+ StoreNoWriteBarrier(rep, elements, offset, value); |
+ return; |
+ } |
+ |
+ WriteBarrierMode barrier_mode = |
+ IsFastSmiElementsKind(kind) ? SKIP_WRITE_BARRIER : UPDATE_WRITE_BARRIER; |
+ if (IsFastDoubleElementsKind(kind)) { |
+ // Make sure we do not store signalling NaNs into double arrays. |
+ value = Float64SilenceNaN(value); |
+ StoreFixedDoubleArrayElement(elements, index, value, mode); |
+ } else { |
+ StoreFixedArrayElement(elements, index, value, barrier_mode, mode); |
+ } |
+} |
+ |
+void CodeStubAssembler::StoreObjectElement(Node* object, Node* key, Node* value, |
+ bool is_jsarray, |
+ ElementsKind elements_kind, |
+ KeyedAccessStoreMode store_mode, |
+ Label* bailout) { |
+ Node* elements = LoadElements(object); |
+ if (IsFastSmiOrObjectElementsKind(elements_kind) && |
+ store_mode != STORE_NO_TRANSITION_HANDLE_COW) { |
+ // Bailout in case of COW elements. |
+ GotoIf(WordNotEqual(LoadMap(elements), |
+ LoadRoot(Heap::kFixedArrayMapRootIndex)), |
+ bailout); |
+ } |
+ // TODO(ishell): introduce TryToIntPtrOrSmi() and use OptimalParameterMode(). |
+ ParameterMode parameter_mode = INTPTR_PARAMETERS; |
+ key = TryToIntptr(key, bailout); |
+ |
+ if (IsFixedTypedArrayElementsKind(elements_kind)) { |
+ // Check if buffer has been neutered. |
+ Node* buffer = LoadObjectField(object, JSArrayBufferView::kBufferOffset); |
+ Node* bitfield = LoadObjectField(buffer, JSArrayBuffer::kBitFieldOffset, |
+ MachineType::Uint32()); |
+ Node* neutered_bit = |
+ Word32And(bitfield, Int32Constant(JSArrayBuffer::WasNeutered::kMask)); |
+ GotoUnless(Word32Equal(neutered_bit, Int32Constant(0)), bailout); |
+ |
+ // Bounds check. |
+ Node* length = UntagParameter( |
+ LoadObjectField(object, JSTypedArray::kLengthOffset), parameter_mode); |
+ |
+ if (store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) { |
+ GotoUnless(IntPtrLessThan(key, IntPtrOrSmiConstant(0, parameter_mode)), |
+ bailout); |
Benedikt Meurer
2016/09/13 09:08:00
Maybe you want to check the upper bound as well, a
Igor Sheludko
2016/09/13 10:33:17
Done. Thanks!
|
+ } else { |
+ DCHECK(store_mode == STANDARD_STORE); |
Benedikt Meurer
2016/09/13 09:08:00
Nit: DCHECK_EQ
Igor Sheludko
2016/09/13 10:33:16
Done.
|
+ GotoUnless(UintPtrLessThan(key, length), bailout); |
+ } |
+ // Backing store = external_pointer + base_pointer. |
+ Node* external_pointer = |
+ LoadObjectField(elements, FixedTypedArrayBase::kExternalPointerOffset, |
+ MachineType::Pointer()); |
+ Node* base_pointer = |
+ LoadObjectField(elements, FixedTypedArrayBase::kBasePointerOffset); |
+ Node* backing_store = IntPtrAdd(external_pointer, base_pointer); |
Benedikt Meurer
2016/09/13 09:08:00
You must not have a GC afterwards before you store
Igor Sheludko
2016/09/13 10:33:17
Done.
|
+ |
+ if (IsFixedFloatElementsKind(elements_kind)) { |
+ // TODO(ishell): move float32 truncation into PrepareValueForWrite. |
+ value = PrepareValueForWrite(value, Representation::Double(), bailout); |
+ if (elements_kind == FLOAT32_ELEMENTS) { |
+ value = TruncateFloat64ToFloat32(value); |
+ } |
+ } else { |
+ value = TryToIntptr(value, bailout); |
Benedikt Meurer
2016/09/13 09:08:00
Maybe add a TODO here, that JS truncation would be
Igor Sheludko
2016/09/13 10:33:16
Done.
|
+ } |
+ return StoreElement(backing_store, elements_kind, key, value, |
+ parameter_mode); |
Benedikt Meurer
2016/09/13 09:08:00
You probably need to insert a Retain for the buffe
Igor Sheludko
2016/09/13 10:33:16
I rearranged the code so that the value preparatio
|
+ } |
+ DCHECK(IsFastSmiOrObjectElementsKind(elements_kind) || |
+ IsFastDoubleElementsKind(elements_kind)); |
+ |
+ Node* length = is_jsarray ? LoadObjectField(object, JSArray::kLengthOffset) |
+ : LoadFixedArrayBaseLength(elements); |
+ length = UntagParameter(length, parameter_mode); |
+ |
+ // In case value is stored into a fast smi array, assure that the value is |
+ // a smi before manipulating the backing store. Otherwise the backing store |
+ // may be left in an invalid state. |
+ if (IsFastSmiElementsKind(elements_kind)) { |
+ GotoUnless(WordIsSmi(value), bailout); |
+ } else if (IsFastDoubleElementsKind(elements_kind)) { |
+ value = PrepareValueForWrite(value, Representation::Double(), bailout); |
+ } |
+ |
+ if (IsGrowStoreMode(store_mode)) { |
+ elements = CheckForCapacityGrow(object, elements, elements_kind, length, |
+ key, parameter_mode, is_jsarray, bailout); |
+ } else { |
+ GotoUnless(UintPtrLessThan(key, length), bailout); |
+ |
+ if ((store_mode == STORE_NO_TRANSITION_HANDLE_COW) && |
+ IsFastSmiOrObjectElementsKind(elements_kind)) { |
+ elements = CopyElementsOnWrite(object, elements, elements_kind, length, |
+ parameter_mode, bailout); |
+ } |
+ } |
+ StoreElement(elements, elements_kind, key, value, parameter_mode); |
+} |
+ |
+Node* CodeStubAssembler::CheckForCapacityGrow(Node* object, Node* elements, |
+ ElementsKind kind, Node* length, |
+ Node* key, ParameterMode mode, |
+ bool is_js_array, |
+ Label* bailout) { |
+ Variable checked_elements(this, MachineRepresentation::kTagged); |
+ Label grow_case(this), no_grow_case(this), done(this); |
+ |
+ Node* condition; |
+ if (IsHoleyElementsKind(kind)) { |
+ condition = UintPtrGreaterThanOrEqual(key, length); |
+ } else { |
+ condition = WordEqual(key, length); |
+ } |
+ Branch(condition, &grow_case, &no_grow_case); |
+ |
+ Bind(&grow_case); |
+ { |
+ Node* current_capacity = |
+ UntagParameter(LoadFixedArrayBaseLength(elements), mode); |
+ |
+ checked_elements.Bind(elements); |
+ |
+ Label fits_capacity(this); |
+ GotoIf(UintPtrLessThan(key, current_capacity), &fits_capacity); |
+ { |
+ Node* new_elements = TryGrowElementsCapacity( |
+ object, elements, kind, key, current_capacity, mode, bailout); |
+ |
+ checked_elements.Bind(new_elements); |
+ Goto(&fits_capacity); |
+ } |
+ Bind(&fits_capacity); |
+ |
+ if (is_js_array) { |
+ Node* new_length = IntPtrAdd(key, IntPtrOrSmiConstant(1, mode)); |
+ StoreObjectFieldNoWriteBarrier(object, JSArray::kLengthOffset, |
+ TagParameter(new_length, mode)); |
+ } |
+ |
+ if (kind == FAST_SMI_ELEMENTS) { |
Benedikt Meurer
2016/09/13 09:08:00
This shouldn't be necessary, it was only necessary
Igor Sheludko
2016/09/13 10:33:16
Indeed, it's not necessary. Thanks!
|
+ // Write zero to ensure that the new element is initialized with some smi. |
+ Node* zero = SmiConstant(Smi::FromInt(0)); |
+ StoreFixedArrayElement(checked_elements.value(), key, zero, |
+ SKIP_WRITE_BARRIER, mode); |
+ } |
+ |
+ Goto(&done); |
+ } |
+ |
+ Bind(&no_grow_case); |
+ { |
+ GotoUnless(UintPtrLessThan(key, length), bailout); |
+ checked_elements.Bind(elements); |
+ Goto(&done); |
+ } |
+ |
+ Bind(&done); |
+ return checked_elements.value(); |
+} |
+ |
+Node* CodeStubAssembler::CopyElementsOnWrite(Node* object, Node* elements, |
+ ElementsKind kind, Node* length, |
+ ParameterMode mode, |
+ Label* bailout) { |
+ Variable new_elements_var(this, MachineRepresentation::kTagged); |
+ Label done(this); |
+ |
+ new_elements_var.Bind(elements); |
+ GotoUnless( |
+ WordEqual(LoadMap(elements), LoadRoot(Heap::kFixedCOWArrayMapRootIndex)), |
+ &done); |
+ { |
+ Node* capacity = UntagParameter(LoadFixedArrayBaseLength(elements), mode); |
+ Node* new_elements = GrowElementsCapacity(object, elements, kind, kind, |
+ length, capacity, mode, bailout); |
+ |
+ new_elements_var.Bind(new_elements); |
+ Goto(&done); |
+ } |
+ |
+ Bind(&done); |
+ return new_elements_var.value(); |
+} |
+ |
Node* CodeStubAssembler::EnumLength(Node* map) { |
Node* bitfield_3 = LoadMapBitField3(map); |
Node* enum_length = BitFieldDecode<Map::EnumLengthBits>(bitfield_3); |