| // Copyright 2018 the V8 project authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "src/builtins/growable-fixed-array-gen.h" |
| |
| #include "src/compiler/code-assembler.h" |
| |
| namespace v8 { |
| namespace internal { |
| |
| void GrowableFixedArray::Push(const TNode<Object> value) { |
| const TNode<IntPtrT> length = var_length_.value(); |
| const TNode<IntPtrT> capacity = var_capacity_.value(); |
| |
| Label grow(this), store(this); |
| Branch(IntPtrEqual(capacity, length), &grow, &store); |
| |
| BIND(&grow); |
| { |
| var_capacity_ = NewCapacity(capacity); |
| var_array_ = ResizeFixedArray(length, var_capacity_.value()); |
| |
| Goto(&store); |
| } |
| |
| BIND(&store); |
| { |
| const TNode<FixedArray> array = var_array_.value(); |
| UnsafeStoreFixedArrayElement(array, length, value); |
| |
| var_length_ = IntPtrAdd(length, IntPtrConstant(1)); |
| } |
| } |
| |
| TNode<FixedArray> GrowableFixedArray::ToFixedArray() { |
| return ResizeFixedArray(length(), length()); |
| } |
| |
| TNode<JSArray> GrowableFixedArray::ToJSArray(const TNode<Context> context) { |
| const ElementsKind kind = PACKED_ELEMENTS; |
| |
| const TNode<NativeContext> native_context = LoadNativeContext(context); |
| const TNode<Map> array_map = LoadJSArrayElementsMap(kind, native_context); |
| |
| // Shrink to fit if necessary. |
| { |
| Label next(this); |
| |
| const TNode<IntPtrT> length = var_length_.value(); |
| const TNode<IntPtrT> capacity = var_capacity_.value(); |
| |
| GotoIf(WordEqual(length, capacity), &next); |
| |
| var_array_ = ResizeFixedArray(length, length); |
| var_capacity_ = length; |
| Goto(&next); |
| |
| BIND(&next); |
| } |
| |
| const TNode<Smi> result_length = SmiTag(length()); |
| const TNode<JSArray> result = |
| AllocateJSArray(array_map, var_array_.value(), result_length); |
| return result; |
| } |
| |
| TNode<IntPtrT> GrowableFixedArray::NewCapacity( |
| TNode<IntPtrT> current_capacity) { |
| CSA_ASSERT(this, |
| IntPtrGreaterThanOrEqual(current_capacity, IntPtrConstant(0))); |
| |
| // Growth rate is analog to JSObject::NewElementsCapacity: |
| // new_capacity = (current_capacity + (current_capacity >> 1)) + 16. |
| |
| const TNode<IntPtrT> new_capacity = |
| IntPtrAdd(IntPtrAdd(current_capacity, WordShr(current_capacity, 1)), |
| IntPtrConstant(16)); |
| |
| return new_capacity; |
| } |
| |
| TNode<FixedArray> GrowableFixedArray::ResizeFixedArray( |
| const TNode<IntPtrT> element_count, const TNode<IntPtrT> new_capacity) { |
| CSA_ASSERT(this, IntPtrGreaterThanOrEqual(element_count, IntPtrConstant(0))); |
| CSA_ASSERT(this, IntPtrGreaterThanOrEqual(new_capacity, IntPtrConstant(0))); |
| CSA_ASSERT(this, IntPtrGreaterThanOrEqual(new_capacity, element_count)); |
| |
| const TNode<FixedArray> from_array = var_array_.value(); |
| |
| CodeStubAssembler::ExtractFixedArrayFlags flags; |
| flags |= CodeStubAssembler::ExtractFixedArrayFlag::kFixedArrays; |
| TNode<FixedArray> to_array = CAST(ExtractFixedArray( |
| from_array, base::Optional<TNode<IntPtrT>>(base::nullopt), |
| base::Optional<TNode<IntPtrT>>(element_count), |
| base::Optional<TNode<IntPtrT>>(new_capacity), flags)); |
| |
| return to_array; |
| } |
| |
| } // namespace internal |
| } // namespace v8 |