1 // Copyright 2018 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/builtins/growable-fixed-array-gen.h"
6
7 #include "src/compiler/code-assembler.h"
8
9 namespace v8 {
10 namespace internal {
11
Push(const TNode<Object> value)12 void GrowableFixedArray::Push(const TNode<Object> value) {
13 const TNode<IntPtrT> length = var_length_.value();
14 const TNode<IntPtrT> capacity = var_capacity_.value();
15
16 Label grow(this), store(this);
17 Branch(IntPtrEqual(capacity, length), &grow, &store);
18
19 BIND(&grow);
20 {
21 var_capacity_ = NewCapacity(capacity);
22 var_array_ = ResizeFixedArray(length, var_capacity_.value());
23
24 Goto(&store);
25 }
26
27 BIND(&store);
28 {
29 const TNode<FixedArray> array = var_array_.value();
30 UnsafeStoreFixedArrayElement(array, length, value);
31
32 var_length_ = IntPtrAdd(length, IntPtrConstant(1));
33 }
34 }
35
ToFixedArray()36 TNode<FixedArray> GrowableFixedArray::ToFixedArray() {
37 return ResizeFixedArray(length(), length());
38 }
39
ToJSArray(const TNode<Context> context)40 TNode<JSArray> GrowableFixedArray::ToJSArray(const TNode<Context> context) {
41 const ElementsKind kind = PACKED_ELEMENTS;
42
43 const TNode<NativeContext> native_context = LoadNativeContext(context);
44 const TNode<Map> array_map = LoadJSArrayElementsMap(kind, native_context);
45
46 // Shrink to fit if necessary.
47 {
48 Label next(this);
49
50 const TNode<IntPtrT> length = var_length_.value();
51 const TNode<IntPtrT> capacity = var_capacity_.value();
52
53 GotoIf(WordEqual(length, capacity), &next);
54
55 var_array_ = ResizeFixedArray(length, length);
56 var_capacity_ = length;
57 Goto(&next);
58
59 BIND(&next);
60 }
61
62 const TNode<Smi> result_length = SmiTag(length());
63 const TNode<JSArray> result =
64 AllocateJSArray(array_map, var_array_.value(), result_length);
65 return result;
66 }
67
NewCapacity(TNode<IntPtrT> current_capacity)68 TNode<IntPtrT> GrowableFixedArray::NewCapacity(
69 TNode<IntPtrT> current_capacity) {
70 CSA_ASSERT(this,
71 IntPtrGreaterThanOrEqual(current_capacity, IntPtrConstant(0)));
72
73 // Growth rate is analog to JSObject::NewElementsCapacity:
74 // new_capacity = (current_capacity + (current_capacity >> 1)) + 16.
75
76 const TNode<IntPtrT> new_capacity =
77 IntPtrAdd(IntPtrAdd(current_capacity, WordShr(current_capacity, 1)),
78 IntPtrConstant(16));
79
80 return new_capacity;
81 }
82
ResizeFixedArray(const TNode<IntPtrT> element_count,const TNode<IntPtrT> new_capacity)83 TNode<FixedArray> GrowableFixedArray::ResizeFixedArray(
84 const TNode<IntPtrT> element_count, const TNode<IntPtrT> new_capacity) {
85 CSA_ASSERT(this, IntPtrGreaterThanOrEqual(element_count, IntPtrConstant(0)));
86 CSA_ASSERT(this, IntPtrGreaterThanOrEqual(new_capacity, IntPtrConstant(0)));
87 CSA_ASSERT(this, IntPtrGreaterThanOrEqual(new_capacity, element_count));
88
89 const TNode<FixedArray> from_array = var_array_.value();
90
91 CodeStubAssembler::ExtractFixedArrayFlags flags;
92 flags |= CodeStubAssembler::ExtractFixedArrayFlag::kFixedArrays;
93 TNode<FixedArray> to_array = CAST(ExtractFixedArray(
94 from_array, base::Optional<TNode<IntPtrT>>(base::nullopt),
95 base::Optional<TNode<IntPtrT>>(element_count),
96 base::Optional<TNode<IntPtrT>>(new_capacity), flags));
97
98 return to_array;
99 }
100
101 } // namespace internal
102 } // namespace v8
103