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