• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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_iterator_stub_builder.h"
17 
18 #include "ecmascript/compiler/builtins/linked_hashtable_stub_builder.h"
19 #include "ecmascript/compiler/new_object_stub_builder.h"
20 #include "ecmascript/js_map_iterator.h"
21 #include "ecmascript/js_set_iterator.h"
22 #include "ecmascript/linked_hash_table.h"
23 
24 namespace panda::ecmascript::kungfu {
25 
26 template <typename IteratorType>
CheckCollectionIteratorObj(Label * updateIter,Label * throwException)27 void BuiltinsCollectionIteratorStubBuilder<IteratorType>::CheckCollectionIteratorObj(Label *updateIter,
28                                                                                      Label *throwException)
29 {
30     // check target obj
31     auto jsType = std::is_same_v<IteratorType, JSSetIterator> ? JSType::JS_SET_ITERATOR : JSType::JS_MAP_ITERATOR;
32     GateRef isJsCollectionIteratorObj = IsJSObjectType(thisValue_, jsType);
33     BRANCH(isJsCollectionIteratorObj, updateIter, throwException);
34 }
35 
36 template<typename IteratorType>
CreateIterValueForEntry(GateRef key,GateRef value)37 GateRef BuiltinsCollectionIteratorStubBuilder<IteratorType>::CreateIterValueForEntry(GateRef key, GateRef value)
38 {
39     NewObjectStubBuilder newBuilder(this);
40     GateRef elements = newBuilder.NewTaggedArray(glue_, Int32(2));    // 2: length of array to store [key, value] is 2
41     SetValueToTaggedArray(VariableType::JS_ANY(), glue_, elements, Int32(0), key);   // 0: key
42     SetValueToTaggedArray(VariableType::JS_ANY(), glue_, elements, Int32(1), value); // 1: value
43     return newBuilder.CreateArrayFromList(glue_, elements, Int32(Elements::ToUint(ElementsKind::TAGGED)));
44 }
45 
46 template <typename IteratorType>
Next(Variable * result,Label * exit)47 void BuiltinsCollectionIteratorStubBuilder<IteratorType>::Next(Variable *result,
48                                                                Label *exit)
49 {
50     auto env = GetEnvironment();
51     Label updateIter(env);
52     Label checkLinked(env);
53     Label getNext(env);
54     Label iterDone(env);
55     Label throwException(env);
56 
57     DEFVARIABLE(res, VariableType::JS_ANY(), TaggedUndefined());
58     DEFVARIABLE(iterValue, VariableType::JS_ANY(), TaggedUndefined());
59     DEFVARIABLE(isDone, VariableType::JS_ANY(), TaggedTrue());
60     DEFVARIABLE(iteratedLinkedObj, VariableType::JS_ANY(), TaggedUndefined());
61     DEFVARIABLE(itemKind, VariableType::INT32(), GetIterationKind());
62     DEFVARIABLE(totalElements, VariableType::INT32(), Int32(0));
63     DEFVARIABLE(key, VariableType::JS_ANY(), TaggedUndefined());
64 
65     // check target obj
66     CheckCollectionIteratorObj(&updateIter, &throwException);
67     Bind(&updateIter);
68     {
69         UpdateIter(&checkLinked);
70     }
71 
72     Bind(&checkLinked);
73     {
74         iteratedLinkedObj = GetIteratedLinkedObj();
75         BRANCH(TaggedIsUndefined(*iteratedLinkedObj), &iterDone, &getNext);
76     }
77 
78     Bind(&getNext);
79     {
80         DEFVARIABLE(index, VariableType::INT32(), GetNextIndex());
81         if constexpr (std::is_same_v<IteratorType, JSMapIterator>) {
82             LinkedHashTableStubBuilder<LinkedHashMap, LinkedHashMapObject> linkedHashTableStubBuilder(this, glue_);
83             totalElements = Int32Add(linkedHashTableStubBuilder.GetNumberOfElements(*iteratedLinkedObj),
84                                      linkedHashTableStubBuilder.GetNumberOfDeletedElements(*iteratedLinkedObj));
85         } else {
86             LinkedHashTableStubBuilder<LinkedHashSet, LinkedHashSetObject> linkedHashTableStubBuilder(this, glue_);
87             totalElements = Int32Add(linkedHashTableStubBuilder.GetNumberOfElements(*iteratedLinkedObj),
88                                      linkedHashTableStubBuilder.GetNumberOfDeletedElements(*iteratedLinkedObj));
89         }
90         Label keyIsNotHole(env);
91         Label loopHead(env);
92         Label loopEnd(env);
93         Label next(env);
94         Label loopExit(env);
95         Jump(&loopHead);
96         LoopBegin(&loopHead);
97         {
98             BRANCH(Int32LessThan(*index, *totalElements), &next, &loopExit);
99             Bind(&next);
100             {
101                 if constexpr (std::is_same_v<IteratorType, JSMapIterator>) {
102                     LinkedHashTableStubBuilder<LinkedHashMap, LinkedHashMapObject> linkedHashTableStubBuilder(this,
103                                                                                                               glue_);
104                     key = linkedHashTableStubBuilder.GetKey(*iteratedLinkedObj, *index);
105                 } else {
106                     LinkedHashTableStubBuilder<LinkedHashSet, LinkedHashSetObject> linkedHashTableStubBuilder(this,
107                                                                                                               glue_);
108                     key = linkedHashTableStubBuilder.GetKey(*iteratedLinkedObj, *index);
109                 }
110                 BRANCH(TaggedIsHole(*key), &loopEnd, &keyIsNotHole);
111                 Bind(&keyIsNotHole);
112                 {
113                     SetNextIndex(Int32Add(*index, Int32(1)));
114                     Label defaultLabel(env);
115                     const uint32_t TOTAL_ITERATOR_KINDS = 3; // 3: iterator has 3 kinds [key, value, key_and_value]
116                     Label labelBuffer[TOTAL_ITERATOR_KINDS] = {Label(env), Label(env), Label(env)};
117                     int64_t valueBuffer[TOTAL_ITERATOR_KINDS] = {static_cast<int64_t>(IterationKind::KEY),
118                                                                  static_cast<int64_t>(IterationKind::VALUE),
119                                                                  static_cast<int64_t>(IterationKind::KEY_AND_VALUE)};
120                     // 3 : this switch has 3 case
121                     Switch(*itemKind, &defaultLabel, valueBuffer, labelBuffer, TOTAL_ITERATOR_KINDS);
122 
123                     // ITERATION_KIND_KEY
124                     // 0 : index of this buffer
125                     Bind(&labelBuffer[0]);
126                     {
127                         isDone = TaggedFalse();
128                         iterValue = *key;
129                         Jump(&iterDone);
130                     }
131 
132                     // ITERATION_KIND_VALUE
133                     // 1 : index of this buffer
134                     Bind(&labelBuffer[1]);
135                     {
136                         isDone = TaggedFalse();
137                         if constexpr (std::is_same_v<IteratorType, JSMapIterator>) {
138                             LinkedHashTableStubBuilder<LinkedHashMap, LinkedHashMapObject> linkedHashTableStubBuilder(
139                                 this, glue_);
140                             iterValue = linkedHashTableStubBuilder.GetValue(*iteratedLinkedObj, *index);
141                         } else {
142                             iterValue = *key;
143                         }
144                         Jump(&iterDone);
145                     }
146 
147                     // ITERATION_KIND_KEY_AND_VALUE
148                     // 2 : index of this buffer
149                     Bind(&labelBuffer[2]);
150                     {
151                         Label afterCreate(env);
152                         DEFVARIABLE(value, VariableType::JS_ANY(), TaggedUndefined());
153                         if constexpr (std::is_same_v<IteratorType, JSMapIterator>) {
154                             LinkedHashTableStubBuilder<LinkedHashMap, LinkedHashMapObject> linkedHashTableStubBuilder(
155                                 this, glue_);
156                             value = linkedHashTableStubBuilder.GetValue(*iteratedLinkedObj, *index);
157                         } else {
158                             value = *key;
159                         }
160                         iterValue = CreateIterValueForEntry(*key, *value);
161                         isDone = TaggedFalse();
162                         Jump(&iterDone);
163                     }
164 
165                     Bind(&defaultLabel);
166                     {
167                         FatalPrint(glue_, {Int32(GET_MESSAGE_STRING_ID(ThisBranchIsUnreachable))});
168                         Jump(exit);
169                     }
170                 }
171             }
172         }
173         Bind(&loopEnd);
174         index = Int32Add(*index, Int32(1));
175         LoopEnd(&loopHead);
176         Bind(&loopExit);
177         SetIteratedLinkedObj(TaggedUndefined());
178         Jump(&iterDone);
179     }
180 
181     Bind(&iterDone);
182     {
183         Label afterCreate(env);
184         NewObjectStubBuilder newBuilder(this);
185         newBuilder.CreateJSIteratorResult(glue_, &res, *iterValue, *isDone, &afterCreate);
186         Bind(&afterCreate);
187         result->WriteVariable(*res);
188         Jump(exit);
189     }
190 
191     Bind(&throwException);
192     {
193         if constexpr (std::is_same_v<IteratorType, JSMapIterator>) {
194             GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(MapIteratorTypeError));
195             CallRuntime(glue_, RTSTUB_ID(ThrowTypeError), {IntToTaggedInt(taggedId)});
196         } else {
197             GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(SetIteratorTypeError));
198             CallRuntime(glue_, RTSTUB_ID(ThrowTypeError), {IntToTaggedInt(taggedId)});
199         }
200         result->WriteVariable(Exception());
201         Jump(exit);
202     }
203 }
204 
205 template void BuiltinsCollectionIteratorStubBuilder<JSMapIterator>::Next(Variable *result,
206                                                                          Label *exit);
207 template void BuiltinsCollectionIteratorStubBuilder<JSSetIterator>::Next(Variable *result,
208                                                                          Label *exit);
209 
210 template <typename IteratorType>
UpdateIter(Label * iterUpdated)211 void BuiltinsCollectionIteratorStubBuilder<IteratorType>::UpdateIter(Label *iterUpdated)
212 {
213     auto env = GetEnvironment();
214     Label checkNextTable(env);
215     Label getNext(env);
216     DEFVARIABLE(nextTable, VariableType::JS_ANY(), Circuit::NullGate());
217     DEFVARIABLE(iteratedLinkedObj, VariableType::JS_ANY(), GetIteratedLinkedObj());
218 
219     BRANCH(TaggedIsUndefined(*iteratedLinkedObj), iterUpdated, &checkNextTable);
220 
221     Bind(&checkNextTable);
222     {
223         nextTable = GetNextTable(*iteratedLinkedObj);
224         BRANCH(TaggedIsHole(*nextTable), iterUpdated, &getNext);
225     }
226 
227     Bind(&getNext);
228     {
229         DEFVARIABLE(index, VariableType::INT32(), GetNextIndex());
230         Label loopHead(env);
231         Label loopEnd(env);
232         Label next(env);
233         Label loopExit(env);
234         Jump(&loopHead);
235         LoopBegin(&loopHead);
236         {
237             BRANCH(TaggedIsHole(*nextTable), &loopExit, &next);
238             Bind(&next);
239             {
240                 DEFVARIABLE(DeletedElementsAt, VariableType::INT32(), Int32(0));
241                 if constexpr (std::is_same_v<IteratorType, JSMapIterator>) {
242                     LinkedHashTableStubBuilder<LinkedHashMap, LinkedHashMapObject> linkedHashTableStubBuilder(this,
243                                                                                                               glue_);
244                     DeletedElementsAt = linkedHashTableStubBuilder.GetDeletedElementsAt(*iteratedLinkedObj, *index);
245                 } else {
246                     LinkedHashTableStubBuilder<LinkedHashSet, LinkedHashSetObject> linkedHashTableStubBuilder(this,
247                                                                                                               glue_);
248                     DeletedElementsAt = linkedHashTableStubBuilder.GetDeletedElementsAt(*iteratedLinkedObj, *index);
249                 }
250                 index = Int32Sub(*index, *DeletedElementsAt);
251                 iteratedLinkedObj = *nextTable;
252                 nextTable = GetNextTable(*iteratedLinkedObj);
253                 Jump(&loopEnd);
254             }
255         }
256         Bind(&loopEnd);
257         LoopEnd(&loopHead);
258         Bind(&loopExit);
259         SetIteratedLinkedObj(*iteratedLinkedObj);
260         SetNextIndex(*index);
261         Jump(iterUpdated);
262     }
263 }
264 
265 template void BuiltinsCollectionIteratorStubBuilder<JSMapIterator>::UpdateIter(Label *iterUpdated);
266 template void BuiltinsCollectionIteratorStubBuilder<JSSetIterator>::UpdateIter(Label *iterUpdated);
267 
268 }  // namespace panda::ecmascript::kungfu
269