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(TNode<Object> const value)12 void GrowableFixedArray::Push(TNode<Object> const value) {
13 TNode<IntPtrT> const length = var_length_.value();
14 TNode<IntPtrT> const 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 TNode<FixedArray> const array = var_array_.value();
30 StoreFixedArrayElement(array, length, value);
31
32 var_length_ = IntPtrAdd(length, IntPtrConstant(1));
33 }
34 }
35
ToJSArray(TNode<Context> const context)36 TNode<JSArray> GrowableFixedArray::ToJSArray(TNode<Context> const context) {
37 const ElementsKind kind = PACKED_ELEMENTS;
38
39 TNode<Context> const native_context = LoadNativeContext(context);
40 TNode<Map> const array_map = LoadJSArrayElementsMap(kind, native_context);
41
42 // Shrink to fit if necessary.
43 {
44 Label next(this);
45
46 TNode<IntPtrT> const length = var_length_.value();
47 TNode<IntPtrT> const capacity = var_capacity_.value();
48
49 GotoIf(WordEqual(length, capacity), &next);
50
51 var_array_ = ResizeFixedArray(length, length);
52 var_capacity_ = length;
53 Goto(&next);
54
55 BIND(&next);
56 }
57
58 TNode<Smi> const result_length = SmiTag(length());
59 TNode<JSArray> const result =
60 CAST(AllocateUninitializedJSArrayWithoutElements(array_map, result_length,
61 nullptr));
62
63 StoreObjectField(result, JSObject::kElementsOffset, var_array_.value());
64
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 TNode<IntPtrT> const new_capacity =
77 IntPtrAdd(IntPtrAdd(current_capacity, WordShr(current_capacity, 1)),
78 IntPtrConstant(16));
79
80 return new_capacity;
81 }
82
ResizeFixedArray(TNode<IntPtrT> const element_count,TNode<IntPtrT> const new_capacity)83 TNode<FixedArray> GrowableFixedArray::ResizeFixedArray(
84 TNode<IntPtrT> const element_count, TNode<IntPtrT> const 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 TNode<FixedArray> const 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, nullptr, element_count, new_capacity, flags));
95
96 return to_array;
97 }
98
99 } // namespace internal
100 } // namespace v8
101