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