• 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(glue_, 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, GetCurrentGlobalEnv());
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_, GetCurrentGlobalEnv());
83             totalElements = Int32Add(linkedHashTableStubBuilder.GetNumberOfElements(*iteratedLinkedObj),
84                                      linkedHashTableStubBuilder.GetNumberOfDeletedElements(*iteratedLinkedObj));
85         } else {
86             LinkedHashTableStubBuilder<LinkedHashSet, LinkedHashSetObject> linkedHashTableStubBuilder(this, glue_, GetCurrentGlobalEnv());
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_, GetCurrentGlobalEnv());
104                     key = linkedHashTableStubBuilder.GetKey(*iteratedLinkedObj, *index);
105                 } else {
106                     LinkedHashTableStubBuilder<LinkedHashSet, LinkedHashSetObject> linkedHashTableStubBuilder(this,
107                         glue_, GetCurrentGlobalEnv());
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_, GetCurrentGlobalEnv());
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_, GetCurrentGlobalEnv());
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, GetCurrentGlobalEnv());
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             CallRuntimeWithGlobalEnv(glue_, GetCurrentGlobalEnv(),
196                 RTSTUB_ID(ThrowTypeError), {IntToTaggedInt(taggedId)});
197         } else {
198             GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(SetIteratorTypeError));
199             CallRuntimeWithGlobalEnv(glue_, GetCurrentGlobalEnv(),
200                 RTSTUB_ID(ThrowTypeError), {IntToTaggedInt(taggedId)});
201         }
202         result->WriteVariable(Exception());
203         Jump(exit);
204     }
205 }
206 
207 template void BuiltinsCollectionIteratorStubBuilder<JSMapIterator>::Next(Variable *result,
208                                                                          Label *exit);
209 template void BuiltinsCollectionIteratorStubBuilder<JSSetIterator>::Next(Variable *result,
210                                                                          Label *exit);
211 
212 template <typename IteratorType>
UpdateIter(Label * iterUpdated)213 void BuiltinsCollectionIteratorStubBuilder<IteratorType>::UpdateIter(Label *iterUpdated)
214 {
215     auto env = GetEnvironment();
216     Label checkNextTable(env);
217     Label getNext(env);
218     DEFVARIABLE(nextTable, VariableType::JS_ANY(), Circuit::NullGate());
219     DEFVARIABLE(iteratedLinkedObj, VariableType::JS_ANY(), GetIteratedLinkedObj());
220 
221     BRANCH(TaggedIsUndefined(*iteratedLinkedObj), iterUpdated, &checkNextTable);
222 
223     Bind(&checkNextTable);
224     {
225         nextTable = GetNextTable(*iteratedLinkedObj);
226         BRANCH(TaggedIsHole(*nextTable), iterUpdated, &getNext);
227     }
228 
229     Bind(&getNext);
230     {
231         DEFVARIABLE(index, VariableType::INT32(), GetNextIndex());
232         Label loopHead(env);
233         Label loopEnd(env);
234         Label next(env);
235         Label loopExit(env);
236         Jump(&loopHead);
237         LoopBegin(&loopHead);
238         {
239             BRANCH(TaggedIsHole(*nextTable), &loopExit, &next);
240             Bind(&next);
241             {
242                 DEFVARIABLE(DeletedElementsAt, VariableType::INT32(), Int32(0));
243                 if constexpr (std::is_same_v<IteratorType, JSMapIterator>) {
244                     LinkedHashTableStubBuilder<LinkedHashMap, LinkedHashMapObject> linkedHashTableStubBuilder(this,
245                         glue_, GetCurrentGlobalEnv());
246                     DeletedElementsAt = linkedHashTableStubBuilder.GetDeletedElementsAt(*iteratedLinkedObj, *index);
247                 } else {
248                     LinkedHashTableStubBuilder<LinkedHashSet, LinkedHashSetObject> linkedHashTableStubBuilder(this,
249                         glue_, GetCurrentGlobalEnv());
250                     DeletedElementsAt = linkedHashTableStubBuilder.GetDeletedElementsAt(*iteratedLinkedObj, *index);
251                 }
252                 index = Int32Sub(*index, *DeletedElementsAt);
253                 iteratedLinkedObj = *nextTable;
254                 nextTable = GetNextTable(*iteratedLinkedObj);
255                 Jump(&loopEnd);
256             }
257         }
258         Bind(&loopEnd);
259         LoopEnd(&loopHead);
260         Bind(&loopExit);
261         SetIteratedLinkedObj(*iteratedLinkedObj);
262         SetNextIndex(*index);
263         Jump(iterUpdated);
264     }
265 }
266 
267 template void BuiltinsCollectionIteratorStubBuilder<JSMapIterator>::UpdateIter(Label *iterUpdated);
268 template void BuiltinsCollectionIteratorStubBuilder<JSSetIterator>::UpdateIter(Label *iterUpdated);
269 
270 }  // namespace panda::ecmascript::kungfu
271