| Index: src/code-stub-assembler.cc
|
| diff --git a/src/code-stub-assembler.cc b/src/code-stub-assembler.cc
|
| index 93e98713fb7509165afef9be23af0f07808f3c9d..236edd8e5bfc2794337c7ffe11abec7a1769576b 100644
|
| --- a/src/code-stub-assembler.cc
|
| +++ b/src/code-stub-assembler.cc
|
| @@ -1512,51 +1512,167 @@ void CodeStubAssembler::FillFixedArrayWithValue(
|
| }
|
| }
|
|
|
| -void CodeStubAssembler::CopyFixedArrayElements(ElementsKind kind,
|
| - compiler::Node* from_array,
|
| - compiler::Node* to_array,
|
| - compiler::Node* element_count,
|
| - WriteBarrierMode barrier_mode,
|
| - ParameterMode mode) {
|
| - Label test(this);
|
| +void CodeStubAssembler::CopyFixedArrayElements(
|
| + ElementsKind from_kind, Node* from_array, ElementsKind to_kind,
|
| + Node* to_array, Node* element_count, Node* capacity,
|
| + WriteBarrierMode barrier_mode, ParameterMode mode) {
|
| + STATIC_ASSERT(FixedArray::kHeaderSize == FixedDoubleArray::kHeaderSize);
|
| + const int first_element_offset = FixedArray::kHeaderSize - kHeapObjectTag;
|
| + Comment("[ CopyFixedArrayElements");
|
| +
|
| + // Typed array elements are not supported.
|
| + DCHECK(!IsFixedTypedArrayElementsKind(from_kind));
|
| + DCHECK(!IsFixedTypedArrayElementsKind(to_kind));
|
| +
|
| Label done(this);
|
| - bool double_elements = IsFastDoubleElementsKind(kind);
|
| + bool from_double_elements = IsFastDoubleElementsKind(from_kind);
|
| + bool to_double_elements = IsFastDoubleElementsKind(to_kind);
|
| + bool element_size_matches =
|
| + Is64() ||
|
| + IsFastDoubleElementsKind(from_kind) == IsFastDoubleElementsKind(to_kind);
|
| + bool doubles_to_objects_conversion =
|
| + IsFastDoubleElementsKind(from_kind) && IsFastObjectElementsKind(to_kind);
|
| bool needs_write_barrier =
|
| - barrier_mode == UPDATE_WRITE_BARRIER && !IsFastObjectElementsKind(kind);
|
| - Node* limit_offset =
|
| - ElementOffsetFromIndex(IntPtrOrSmiConstant(0, mode), kind, mode,
|
| - FixedArray::kHeaderSize - kHeapObjectTag);
|
| - Variable current_offset(this, MachineType::PointerRepresentation());
|
| - current_offset.Bind(ElementOffsetFromIndex(
|
| - element_count, kind, mode, FixedArray::kHeaderSize - kHeapObjectTag));
|
| - Label decrement(this, ¤t_offset);
|
| + doubles_to_objects_conversion || (barrier_mode == UPDATE_WRITE_BARRIER &&
|
| + IsFastObjectElementsKind(to_kind));
|
| + Node* double_hole =
|
| + Is64() ? Int64Constant(kHoleNanInt64) : Int32Constant(kHoleNanLower32);
|
|
|
| - Branch(WordEqual(current_offset.value(), limit_offset), &done, &decrement);
|
| + if (doubles_to_objects_conversion) {
|
| + // If the copy might trigger a GC, make sure that the FixedArray is
|
| + // pre-initialized with holes to make sure that it's always in a
|
| + // consistent state.
|
| + FillFixedArrayWithValue(to_kind, to_array, IntPtrOrSmiConstant(0, mode),
|
| + capacity, Heap::kTheHoleValueRootIndex, mode);
|
| + } else if (element_count != capacity) {
|
| + FillFixedArrayWithValue(to_kind, to_array, element_count, capacity,
|
| + Heap::kTheHoleValueRootIndex, mode);
|
| + }
|
| +
|
| + Node* limit_offset = ElementOffsetFromIndex(
|
| + IntPtrOrSmiConstant(0, mode), from_kind, mode, first_element_offset);
|
| + Variable var_from_offset(this, MachineType::PointerRepresentation());
|
| + var_from_offset.Bind(ElementOffsetFromIndex(element_count, from_kind, mode,
|
| + first_element_offset));
|
| + // This second variable is used only when the element sizes of source and
|
| + // destination arrays do not match.
|
| + Variable var_to_offset(this, MachineType::PointerRepresentation());
|
| + if (element_size_matches) {
|
| + var_to_offset.Bind(var_from_offset.value());
|
| + } else {
|
| + var_to_offset.Bind(ElementOffsetFromIndex(element_count, to_kind, mode,
|
| + first_element_offset));
|
| + }
|
| +
|
| + Variable* vars[] = {&var_from_offset, &var_to_offset};
|
| + Label decrement(this, 2, vars);
|
| +
|
| + Branch(WordEqual(var_from_offset.value(), limit_offset), &done, &decrement);
|
|
|
| Bind(&decrement);
|
| {
|
| - current_offset.Bind(IntPtrSub(
|
| - current_offset.value(),
|
| - IntPtrConstant(double_elements ? kDoubleSize : kPointerSize)));
|
| + Node* from_offset = IntPtrSub(
|
| + var_from_offset.value(),
|
| + IntPtrConstant(from_double_elements ? kDoubleSize : kPointerSize));
|
| + var_from_offset.Bind(from_offset);
|
| +
|
| + Node* to_offset;
|
| + if (element_size_matches) {
|
| + to_offset = from_offset;
|
| + } else {
|
| + to_offset = IntPtrSub(
|
| + var_to_offset.value(),
|
| + IntPtrConstant(to_double_elements ? kDoubleSize : kPointerSize));
|
| + var_to_offset.Bind(to_offset);
|
| + }
|
| +
|
| + Label next_iter(this), store_double_hole(this);
|
| + Label* if_hole;
|
| + if (doubles_to_objects_conversion) {
|
| + // The target elements array is already preinitialized with holes, so we
|
| + // can just proceed with the next iteration.
|
| + if_hole = &next_iter;
|
| + } else if (IsFastDoubleElementsKind(to_kind)) {
|
| + if_hole = &store_double_hole;
|
| + } else {
|
| + // In all the other cases don't check for holes and copy the data as is.
|
| + if_hole = nullptr;
|
| + }
|
| +
|
| + Node* value = LoadElementAndPrepareForStore(
|
| + from_array, var_from_offset.value(), from_kind, to_kind, if_hole);
|
|
|
| - Node* value =
|
| - Load(double_elements ? MachineType::Float64() : MachineType::Pointer(),
|
| - from_array, current_offset.value());
|
| if (needs_write_barrier) {
|
| - Store(MachineType::PointerRepresentation(), to_array,
|
| - current_offset.value(), value);
|
| - } else if (double_elements) {
|
| - StoreNoWriteBarrier(MachineRepresentation::kFloat64, to_array,
|
| - current_offset.value(), value);
|
| + Store(MachineRepresentation::kTagged, to_array, to_offset, value);
|
| + } else if (to_double_elements) {
|
| + StoreNoWriteBarrier(MachineRepresentation::kFloat64, to_array, to_offset,
|
| + value);
|
| } else {
|
| StoreNoWriteBarrier(MachineType::PointerRepresentation(), to_array,
|
| - current_offset.value(), value);
|
| + to_offset, value);
|
| }
|
| - Node* compare = WordNotEqual(current_offset.value(), limit_offset);
|
| + Goto(&next_iter);
|
| +
|
| + if (if_hole == &store_double_hole) {
|
| + Bind(&store_double_hole);
|
| + // Don't use doubles to store the hole double, since manipulating the
|
| + // signaling NaN used for the hole in C++, e.g. with bit_cast, will
|
| + // change its value on ia32 (the x87 stack is used to return values
|
| + // and stores to the stack silently clear the signalling bit).
|
| + //
|
| + // TODO(danno): When we have a Float32/Float64 wrapper class that
|
| + // preserves double bits during manipulation, remove this code/change
|
| + // this to an indexed Float64 store.
|
| + if (Is64()) {
|
| + StoreNoWriteBarrier(MachineRepresentation::kWord64, to_array, to_offset,
|
| + double_hole);
|
| + } else {
|
| + StoreNoWriteBarrier(MachineRepresentation::kWord32, to_array, to_offset,
|
| + double_hole);
|
| + StoreNoWriteBarrier(MachineRepresentation::kWord32, to_array,
|
| + IntPtrAdd(to_offset, IntPtrConstant(kPointerSize)),
|
| + double_hole);
|
| + }
|
| + Goto(&next_iter);
|
| + }
|
| +
|
| + Bind(&next_iter);
|
| + Node* compare = WordNotEqual(from_offset, limit_offset);
|
| Branch(compare, &decrement, &done);
|
| }
|
|
|
| Bind(&done);
|
| + IncrementCounter(isolate()->counters()->inlined_copied_elements(), 1);
|
| + Comment("] CopyFixedArrayElements");
|
| +}
|
| +
|
| +Node* CodeStubAssembler::LoadElementAndPrepareForStore(Node* array,
|
| + Node* offset,
|
| + ElementsKind from_kind,
|
| + ElementsKind to_kind,
|
| + Label* if_hole) {
|
| + if (IsFastDoubleElementsKind(from_kind)) {
|
| + Node* value =
|
| + LoadDoubleWithHoleCheck(array, offset, if_hole, MachineType::Float64());
|
| + if (!IsFastDoubleElementsKind(to_kind)) {
|
| + value = AllocateHeapNumberWithValue(value);
|
| + }
|
| + return value;
|
| +
|
| + } else {
|
| + Node* value = Load(MachineType::Pointer(), array, offset);
|
| + if (if_hole) {
|
| + GotoIf(WordEqual(value, TheHoleConstant()), if_hole);
|
| + }
|
| + if (IsFastDoubleElementsKind(to_kind)) {
|
| + if (IsFastSmiElementsKind(from_kind)) {
|
| + value = SmiToFloat64(value);
|
| + } else {
|
| + value = LoadHeapNumberValue(value);
|
| + }
|
| + }
|
| + return value;
|
| + }
|
| }
|
|
|
| Node* CodeStubAssembler::CalculateNewElementsCapacity(Node* old_capacity,
|
|
|