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