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 
24 namespace panda::ecmascript::kungfu {
25 
26 template <typename CollectionType>
CheckCollectionObj(Label *thisCollectionObj, Label *slowPath)27 void 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 
35 template <typename CollectionType>
Clear(Variable *result, Label *exit, Label *slowPath)36 void 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 
65 template void BuiltinsCollectionStubBuilder<JSMap>::Clear(Variable *result, Label *exit, Label *slowPath);
66 template void BuiltinsCollectionStubBuilder<JSSet>::Clear(Variable *result, Label *exit, Label *slowPath);
67 
68 template <typename CollectionType>
CreateIterator(Variable *result, Label *exit, Label *slowPath, GateRef kind)69 void 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 
88 template <typename CollectionType>
Values(Variable *result, Label *exit, Label *slowPath)89 void 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 
95 template void BuiltinsCollectionStubBuilder<JSMap>::Values(Variable *result, Label *exit, Label *slowPath);
96 template void BuiltinsCollectionStubBuilder<JSSet>::Values(Variable *result, Label *exit, Label *slowPath);
97 
98 template <typename CollectionType>
Entries(Variable *result, Label *exit, Label *slowPath)99 void 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 
105 template void BuiltinsCollectionStubBuilder<JSMap>::Entries(Variable *result, Label *exit, Label *slowPath);
106 template void BuiltinsCollectionStubBuilder<JSSet>::Entries(Variable *result, Label *exit, Label *slowPath);
107 
108 template <typename CollectionType>
Keys(Variable *result, Label *exit, Label *slowPath)109 void 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 
115 template void BuiltinsCollectionStubBuilder<JSMap>::Keys(Variable *result, Label *exit, Label *slowPath);
116 
117 template <typename CollectionType>
ForEach(Variable *result, Label *exit, Label *slowPath)118 void 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 
153 template void BuiltinsCollectionStubBuilder<JSMap>::ForEach(Variable *result, Label *exit, Label *slowPath);
154 template void BuiltinsCollectionStubBuilder<JSSet>::ForEach(Variable *result, Label *exit, Label *slowPath);
155 
156 template <typename CollectionType>
MapSetOrSetAdd( Variable *result, Label *exit, Label *slowPath, bool isJsMapSet)157 void 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 
186 template <typename CollectionType>
Set(Variable *result, Label *exit, Label *slowPath)187 void BuiltinsCollectionStubBuilder<CollectionType>::Set(Variable *result, Label *exit, Label *slowPath)
188 {
189     MapSetOrSetAdd(result, exit, slowPath, true);
190 }
191 
192 template void BuiltinsCollectionStubBuilder<JSMap>::Set(Variable *result, Label *exit, Label *slowPath);
193 
194 template <typename CollectionType>
Add(Variable *result, Label *exit, Label *slowPath)195 void BuiltinsCollectionStubBuilder<CollectionType>::Add(Variable *result, Label *exit, Label *slowPath)
196 {
197     MapSetOrSetAdd(result, exit, slowPath, false);
198 }
199 
200 template void BuiltinsCollectionStubBuilder<JSSet>::Add(Variable *result, Label *exit, Label *slowPath);
201 
202 template <typename CollectionType>
Delete(Variable *result, Label *exit, Label *slowPath)203 void 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 
225 template void BuiltinsCollectionStubBuilder<JSMap>::Delete(Variable *result, Label *exit, Label *slowPath);
226 template void BuiltinsCollectionStubBuilder<JSSet>::Delete(Variable *result, Label *exit, Label *slowPath);
227 
228 template <typename CollectionType>
Has(Variable *result, Label *exit, Label *slowPath)229 void 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 
251 template void BuiltinsCollectionStubBuilder<JSMap>::Has(Variable *result, Label *exit, Label *slowPath);
252 template void BuiltinsCollectionStubBuilder<JSSet>::Has(Variable *result, Label *exit, Label *slowPath);
253 
254 template <typename CollectionType>
Get(Variable *result, Label *exit, Label *slowPath)255 void 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 
271 template void BuiltinsCollectionStubBuilder<JSMap>::Get(Variable *result, Label *exit, Label *slowPath);
272 
273 }  // namespace panda::ecmascript::kungfu
274