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