1/*
2 * Copyright (c) 2023-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include "ecmascript/compiler/builtins/builtins_collection_stub_builder.h"
17
18#include "ecmascript/compiler/new_object_stub_builder.h"
19#include "ecmascript/linked_hash_table.h"
20#include "ecmascript/js_map.h"
21#include "ecmascript/js_set.h"
22#include "ecmascript/js_iterator.h"
23
24namespace panda::ecmascript::kungfu {
25
26template <typename CollectionType>
27void BuiltinsCollectionStubBuilder<CollectionType>::CheckCollectionObj(Label *thisCollectionObj, Label *slowPath)
28{
29    // check target obj
30    auto jsType = std::is_same_v<CollectionType, JSSet> ? JSType::JS_SET : JSType::JS_MAP;
31    GateRef isJsCollectionObj = IsJSObjectType(thisValue_, jsType);
32    BRANCH(isJsCollectionObj, thisCollectionObj, slowPath);
33}
34
35template <typename CollectionType>
36void BuiltinsCollectionStubBuilder<CollectionType>::Clear(Variable *result, Label *exit, Label *slowPath)
37{
38    auto env = GetEnvironment();
39    Label thisCollectionObj(env);
40    // check target obj
41    CheckCollectionObj(&thisCollectionObj, slowPath);
42
43    Bind(&thisCollectionObj);
44    GateRef linkedTable = GetLinked();
45    GateRef res = Circuit::NullGate();
46    if constexpr (std::is_same_v<CollectionType, JSMap>) {
47        LinkedHashTableStubBuilder<LinkedHashMap, LinkedHashMapObject> linkedHashTableStubBuilder(this, glue_);
48        res = linkedHashTableStubBuilder.Clear(linkedTable);
49    } else {
50        LinkedHashTableStubBuilder<LinkedHashSet, LinkedHashSetObject> linkedHashTableStubBuilder(this, glue_);
51        res = linkedHashTableStubBuilder.Clear(linkedTable);
52    }
53
54    Label exception(env);
55    Label noException(env);
56    BRANCH(TaggedIsException(res), &exception, &noException);
57    Bind(&noException);
58    SetLinked(res);
59    Jump(exit);
60    Bind(&exception);
61    *result = res;
62    Jump(exit);
63}
64
65template void BuiltinsCollectionStubBuilder<JSMap>::Clear(Variable *result, Label *exit, Label *slowPath);
66template void BuiltinsCollectionStubBuilder<JSSet>::Clear(Variable *result, Label *exit, Label *slowPath);
67
68template <typename CollectionType>
69void BuiltinsCollectionStubBuilder<CollectionType>::CreateIterator(Variable *result,
70    Label *exit, Label *slowPath, GateRef kind)
71{
72    auto env = GetEnvironment();
73    Label entry(env);
74    Label thisCollectionObj(env);
75    // check target obj
76    CheckCollectionObj(&thisCollectionObj, slowPath);
77
78    Bind(&thisCollectionObj);
79    NewObjectStubBuilder newBuilder(this);
80    newBuilder.SetGlue(glue_);
81    if constexpr (std::is_same_v<CollectionType, JSSet>) {
82        newBuilder.CreateJSCollectionIterator<JSSetIterator, CollectionType>(result, exit, thisValue_, kind);
83    } else {
84        newBuilder.CreateJSCollectionIterator<JSMapIterator, CollectionType>(result, exit, thisValue_, kind);
85    }
86}
87
88template <typename CollectionType>
89void BuiltinsCollectionStubBuilder<CollectionType>::Values(Variable *result, Label *exit, Label *slowPath)
90{
91    GateRef kind = Int32(static_cast<int32_t>(IterationKind::VALUE));
92    CreateIterator(result, exit, slowPath, kind);
93}
94
95template void BuiltinsCollectionStubBuilder<JSMap>::Values(Variable *result, Label *exit, Label *slowPath);
96template void BuiltinsCollectionStubBuilder<JSSet>::Values(Variable *result, Label *exit, Label *slowPath);
97
98template <typename CollectionType>
99void BuiltinsCollectionStubBuilder<CollectionType>::Entries(Variable *result, Label *exit, Label *slowPath)
100{
101    GateRef kind = Int32(static_cast<int32_t>(IterationKind::KEY_AND_VALUE));
102    CreateIterator(result, exit, slowPath, kind);
103}
104
105template void BuiltinsCollectionStubBuilder<JSMap>::Entries(Variable *result, Label *exit, Label *slowPath);
106template void BuiltinsCollectionStubBuilder<JSSet>::Entries(Variable *result, Label *exit, Label *slowPath);
107
108template <typename CollectionType>
109void BuiltinsCollectionStubBuilder<CollectionType>::Keys(Variable *result, Label *exit, Label *slowPath)
110{
111    GateRef kind = Int32(static_cast<int32_t>(IterationKind::KEY));
112    CreateIterator(result, exit, slowPath, kind);
113}
114
115template void BuiltinsCollectionStubBuilder<JSMap>::Keys(Variable *result, Label *exit, Label *slowPath);
116
117template <typename CollectionType>
118void BuiltinsCollectionStubBuilder<CollectionType>::ForEach(Variable *result, Label *exit, Label *slowPath)
119{
120    auto env = GetEnvironment();
121    Label thisCollectionObj(env);
122    // check target obj
123    CheckCollectionObj(&thisCollectionObj, slowPath);
124
125    Bind(&thisCollectionObj);
126    GateRef callbackFnHandle = GetCallArg0(numArgs_);
127    Label callable(env);
128    // check heap obj
129    Label heapObj(env);
130    BRANCH(TaggedIsHeapObject(callbackFnHandle), &heapObj, slowPath);
131    Bind(&heapObj);
132    BRANCH(IsCallable(callbackFnHandle), &callable, slowPath);
133    Bind(&callable);
134
135    GateRef linkedTable = GetLinked();
136    GateRef res = Circuit::NullGate();
137    GateRef thisArg = GetCallArg1(numArgs_);
138    if constexpr (std::is_same_v<CollectionType, JSMap>) {
139        LinkedHashTableStubBuilder<LinkedHashMap, LinkedHashMapObject> linkedHashTableStubBuilder(this, glue_);
140        res = linkedHashTableStubBuilder.ForEach(thisValue_, linkedTable, callbackFnHandle, thisArg);
141    } else {
142        LinkedHashTableStubBuilder<LinkedHashSet, LinkedHashSetObject> linkedHashTableStubBuilder(this, glue_);
143        res = linkedHashTableStubBuilder.ForEach(thisValue_, linkedTable, callbackFnHandle, thisArg);
144    }
145
146    Label exception(env);
147    BRANCH(TaggedIsException(res), &exception, exit);
148    Bind(&exception);
149    *result = res;
150    Jump(exit);
151}
152
153template void BuiltinsCollectionStubBuilder<JSMap>::ForEach(Variable *result, Label *exit, Label *slowPath);
154template void BuiltinsCollectionStubBuilder<JSSet>::ForEach(Variable *result, Label *exit, Label *slowPath);
155
156template <typename CollectionType>
157void BuiltinsCollectionStubBuilder<CollectionType>::MapSetOrSetAdd(
158    Variable *result, Label *exit, Label *slowPath, bool isJsMapSet)
159{
160    auto env = GetEnvironment();
161    Label thisCollectionObj(env);
162    // check target obj
163    CheckCollectionObj(&thisCollectionObj, slowPath);
164    Bind(&thisCollectionObj);
165    GateRef key = GetCallArg0(numArgs_);
166    // check key
167    Label keyNotHole(env);
168    BRANCH(TaggedIsHole(key), slowPath, &keyNotHole);
169    Bind(&keyNotHole);
170    GateRef value = isJsMapSet ? GetCallArg1(numArgs_) : key;
171    GateRef linkedTable = GetLinked();
172    GateRef res = Circuit::NullGate();
173    if constexpr (std::is_same_v<CollectionType, JSMap>) {
174        LinkedHashTableStubBuilder<LinkedHashMap, LinkedHashMapObject> linkedHashTableStubBuilder(this, glue_);
175        res = linkedHashTableStubBuilder.Insert(linkedTable, key, value);
176    } else {
177        LinkedHashTableStubBuilder<LinkedHashSet, LinkedHashSetObject> linkedHashTableStubBuilder(this, glue_);
178        res = linkedHashTableStubBuilder.Insert(linkedTable, key, value);
179    }
180
181    SetLinked(res);
182    *result = thisValue_;
183    Jump(exit);
184}
185
186template <typename CollectionType>
187void BuiltinsCollectionStubBuilder<CollectionType>::Set(Variable *result, Label *exit, Label *slowPath)
188{
189    MapSetOrSetAdd(result, exit, slowPath, true);
190}
191
192template void BuiltinsCollectionStubBuilder<JSMap>::Set(Variable *result, Label *exit, Label *slowPath);
193
194template <typename CollectionType>
195void BuiltinsCollectionStubBuilder<CollectionType>::Add(Variable *result, Label *exit, Label *slowPath)
196{
197    MapSetOrSetAdd(result, exit, slowPath, false);
198}
199
200template void BuiltinsCollectionStubBuilder<JSSet>::Add(Variable *result, Label *exit, Label *slowPath);
201
202template <typename CollectionType>
203void BuiltinsCollectionStubBuilder<CollectionType>::Delete(Variable *result, Label *exit, Label *slowPath)
204{
205    auto env = GetEnvironment();
206    Label thisCollectionObj(env);
207    // check target obj
208    CheckCollectionObj(&thisCollectionObj, slowPath);
209
210    Bind(&thisCollectionObj);
211    GateRef key = GetCallArg0(numArgs_);
212    GateRef linkedTable = GetLinked();
213    GateRef res = Circuit::NullGate();
214    if constexpr (std::is_same_v<CollectionType, JSMap>) {
215        LinkedHashTableStubBuilder<LinkedHashMap, LinkedHashMapObject> linkedHashTableStubBuilder(this, glue_);
216        res = linkedHashTableStubBuilder.Delete(linkedTable, key);
217    } else {
218        LinkedHashTableStubBuilder<LinkedHashSet, LinkedHashSetObject> linkedHashTableStubBuilder(this, glue_);
219        res = linkedHashTableStubBuilder.Delete(linkedTable, key);
220    }
221    *result = BooleanToTaggedBooleanPtr(res);
222    Jump(exit);
223}
224
225template void BuiltinsCollectionStubBuilder<JSMap>::Delete(Variable *result, Label *exit, Label *slowPath);
226template void BuiltinsCollectionStubBuilder<JSSet>::Delete(Variable *result, Label *exit, Label *slowPath);
227
228template <typename CollectionType>
229void BuiltinsCollectionStubBuilder<CollectionType>::Has(Variable *result, Label *exit, Label *slowPath)
230{
231    auto env = GetEnvironment();
232    Label thisCollectionObj(env);
233    // check target obj
234    CheckCollectionObj(&thisCollectionObj, slowPath);
235
236    Bind(&thisCollectionObj);
237    GateRef key = GetCallArg0(numArgs_);
238    GateRef linkedTable = GetLinked();
239    GateRef res = Circuit::NullGate();
240    if constexpr (std::is_same_v<CollectionType, JSMap>) {
241        LinkedHashTableStubBuilder<LinkedHashMap, LinkedHashMapObject> linkedHashTableStubBuilder(this, glue_);
242        res = linkedHashTableStubBuilder.Has(linkedTable, key);
243    } else {
244        LinkedHashTableStubBuilder<LinkedHashSet, LinkedHashSetObject> linkedHashTableStubBuilder(this, glue_);
245        res = linkedHashTableStubBuilder.Has(linkedTable, key);
246    }
247    *result = BooleanToTaggedBooleanPtr(res);
248    Jump(exit);
249}
250
251template void BuiltinsCollectionStubBuilder<JSMap>::Has(Variable *result, Label *exit, Label *slowPath);
252template void BuiltinsCollectionStubBuilder<JSSet>::Has(Variable *result, Label *exit, Label *slowPath);
253
254template <typename CollectionType>
255void BuiltinsCollectionStubBuilder<CollectionType>::Get(Variable *result, Label *exit, Label *slowPath)
256{
257    auto env = GetEnvironment();
258    Label thisCollectionObj(env);
259    // check target obj
260    CheckCollectionObj(&thisCollectionObj, slowPath);
261
262    Bind(&thisCollectionObj);
263    GateRef key = GetCallArg0(numArgs_);
264    GateRef linkedTable = GetLinked();
265    static_assert(std::is_same_v<CollectionType, JSMap>);
266    LinkedHashTableStubBuilder<LinkedHashMap, LinkedHashMapObject> linkedHashTableStubBuilder(this, glue_);
267    *result = linkedHashTableStubBuilder.Get(linkedTable, key);
268    Jump(exit);
269}
270
271template void BuiltinsCollectionStubBuilder<JSMap>::Get(Variable *result, Label *exit, Label *slowPath);
272
273}  // namespace panda::ecmascript::kungfu
274