• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-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/containers/containers_treeset.h"
17 
18 #include "ecmascript/containers/containers_errors.h"
19 #include "ecmascript/interpreter/interpreter.h"
20 #include "ecmascript/js_api/js_api_tree_set.h"
21 #include "ecmascript/js_api/js_api_tree_set_iterator.h"
22 #include "ecmascript/js_function.h"
23 #include "ecmascript/object_factory.h"
24 #include "ecmascript/tagged_array-inl.h"
25 #include "ecmascript/tagged_tree.h"
26 
27 namespace panda::ecmascript::containers {
TreeSetConstructor(EcmaRuntimeCallInfo * argv)28 JSTaggedValue ContainersTreeSet::TreeSetConstructor(EcmaRuntimeCallInfo *argv)
29 {
30     ASSERT(argv);
31     BUILTINS_API_TRACE(argv->GetThread(), TreeSet, Constructor);
32     JSThread *thread = argv->GetThread();
33     [[maybe_unused]] EcmaHandleScope handleScope(thread);
34     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
35 
36     JSHandle<JSTaggedValue> newTarget = GetNewTarget(argv);
37     if (newTarget->IsUndefined()) {
38         JSTaggedValue error =
39             ContainerError::BusinessError(thread, ErrorFlag::IS_NULL_ERROR,
40                                           "The TreeSet's constructor cannot be directly invoked");
41         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
42     }
43     // new TreeSet
44     JSHandle<JSTaggedValue> constructor = GetConstructor(argv);
45     JSHandle<JSObject> obj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(constructor), newTarget);
46     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
47 
48     // Set set’s internal slot with a new empty List.
49     JSHandle<JSAPITreeSet> set = JSHandle<JSAPITreeSet>::Cast(obj);
50     JSTaggedValue internal = TaggedTreeSet::Create(thread);
51     set->SetTreeSet(thread, internal);
52 
53     // If comparefn was supplied, let compare be comparefn; else let compare be hole.
54     JSHandle<JSTaggedValue> compareFn(GetCallArg(argv, 0));
55     if (compareFn->IsUndefined() || compareFn->IsNull()) {
56         return set.GetTaggedValue();
57     }
58     if (!compareFn->IsCallable()) {
59         JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, compareFn.GetTaggedValue());
60         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
61         CString errorMsg =
62             "The type of \"comparefn\" must be callable. Received value is: " + ConvertToString(*result);
63         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
64         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
65     }
66 
67     TaggedTreeSet::Cast(internal.GetTaggedObject())->SetCompare(thread, compareFn.GetTaggedValue());
68     return set.GetTaggedValue();
69 }
70 
Add(EcmaRuntimeCallInfo * argv)71 JSTaggedValue ContainersTreeSet::Add(EcmaRuntimeCallInfo *argv)
72 {
73     ASSERT(argv);
74     BUILTINS_API_TRACE(argv->GetThread(), TreeSet, Add);
75     JSThread *thread = argv->GetThread();
76     [[maybe_unused]] EcmaHandleScope handleScope(thread);
77     // get and check this set
78     JSHandle<JSTaggedValue> self = GetThis(argv);
79     if (!self->IsJSAPITreeSet()) {
80         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeSet()) {
81             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
82         } else {
83             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
84                                                                 "The add method cannot be bound");
85             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
86         }
87     }
88 
89     JSHandle<JSTaggedValue> value = GetCallArg(argv, 0);
90     JSHandle<JSAPITreeSet> set = JSHandle<JSAPITreeSet>::Cast(self);
91     JSAPITreeSet::Add(thread, set, value);
92     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
93     return JSTaggedValue::True();
94 }
95 
Remove(EcmaRuntimeCallInfo * argv)96 JSTaggedValue ContainersTreeSet::Remove(EcmaRuntimeCallInfo *argv)
97 {
98     BUILTINS_API_TRACE(argv->GetThread(), TreeSet, Remove);
99     JSThread *thread = argv->GetThread();
100     [[maybe_unused]] EcmaHandleScope handleScope(thread);
101     // get and check this set
102     JSHandle<JSTaggedValue> self = GetThis(argv);
103     if (!self->IsJSAPITreeSet()) {
104         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeSet()) {
105             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
106         } else {
107             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
108                                                                 "The remove method cannot be bound");
109             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
110         }
111     }
112 
113     JSHandle<JSAPITreeSet> set = JSHandle<JSAPITreeSet>::Cast(self);
114     JSHandle<JSTaggedValue> key = GetCallArg(argv, 0);
115     return GetTaggedBoolean(JSAPITreeSet::Delete(thread, set, key));
116 }
117 
Has(EcmaRuntimeCallInfo * argv)118 JSTaggedValue ContainersTreeSet::Has(EcmaRuntimeCallInfo *argv)
119 {
120     BUILTINS_API_TRACE(argv->GetThread(), TreeSet, Has);
121     JSThread *thread = argv->GetThread();
122     [[maybe_unused]] EcmaHandleScope handleScope(thread);
123     // get and check this set
124     JSHandle<JSTaggedValue> self(GetThis(argv));
125     if (!self->IsJSAPITreeSet()) {
126         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeSet()) {
127             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
128         } else {
129             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
130                                                                 "The has method cannot be bound");
131             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
132         }
133     }
134 
135     JSHandle<JSTaggedValue> key = GetCallArg(argv, 0);
136     JSHandle<JSAPITreeSet> set = JSHandle<JSAPITreeSet>::Cast(self);
137 
138     bool flag = JSAPITreeSet::Has(thread, JSHandle<JSAPITreeSet>::Cast(set), key);
139     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
140     return GetTaggedBoolean(flag);
141 }
142 
GetFirstValue(EcmaRuntimeCallInfo * argv)143 JSTaggedValue ContainersTreeSet::GetFirstValue(EcmaRuntimeCallInfo *argv)
144 {
145     BUILTINS_API_TRACE(argv->GetThread(), TreeSet, GetFirstValue);
146     JSThread *thread = argv->GetThread();
147     [[maybe_unused]] EcmaHandleScope handleScope(thread);
148     // get and check this set
149     JSHandle<JSTaggedValue> self(GetThis(argv));
150     if (!self->IsJSAPITreeSet()) {
151         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeSet()) {
152             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
153         } else {
154             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
155                                                                 "The getFirstValue method cannot be bound");
156             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
157         }
158     }
159 
160     JSHandle<JSAPITreeSet> set = JSHandle<JSAPITreeSet>::Cast(self);
161     return TaggedTreeSet::Cast(set->GetTreeSet().GetTaggedObject())->GetFirstKey();
162 }
163 
GetLastValue(EcmaRuntimeCallInfo * argv)164 JSTaggedValue ContainersTreeSet::GetLastValue(EcmaRuntimeCallInfo *argv)
165 {
166     BUILTINS_API_TRACE(argv->GetThread(), TreeSet, GetLastValue);
167     JSThread *thread = argv->GetThread();
168     [[maybe_unused]] EcmaHandleScope handleScope(thread);
169     // get and check this set
170     JSHandle<JSTaggedValue> self(GetThis(argv));
171     if (!self->IsJSAPITreeSet()) {
172         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeSet()) {
173             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
174         } else {
175             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
176                                                                 "The getLastValue method cannot be bound");
177             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
178         }
179     }
180 
181     JSHandle<JSAPITreeSet> set = JSHandle<JSAPITreeSet>::Cast(self);
182     return TaggedTreeSet::Cast(set->GetTreeSet().GetTaggedObject())->GetLastKey();
183 }
184 
Clear(EcmaRuntimeCallInfo * argv)185 JSTaggedValue ContainersTreeSet::Clear(EcmaRuntimeCallInfo *argv)
186 {
187     BUILTINS_API_TRACE(argv->GetThread(), TreeSet, Clear);
188     JSThread *thread = argv->GetThread();
189     [[maybe_unused]] EcmaHandleScope handleScope(thread);
190     // get and check this set
191     JSHandle<JSTaggedValue> self(GetThis(argv));
192     if (!self->IsJSAPITreeSet()) {
193         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeSet()) {
194             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
195         } else {
196             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
197                                                                 "The clear method cannot be bound");
198             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
199         }
200     }
201 
202     JSAPITreeSet::Clear(thread, JSHandle<JSAPITreeSet>::Cast(self));
203     return JSTaggedValue::Undefined();
204 }
205 
GetLowerValue(EcmaRuntimeCallInfo * argv)206 JSTaggedValue ContainersTreeSet::GetLowerValue(EcmaRuntimeCallInfo *argv)
207 {
208     BUILTINS_API_TRACE(argv->GetThread(), TreeSet, GetLowerValue);
209     JSThread *thread = argv->GetThread();
210     [[maybe_unused]] EcmaHandleScope handleScope(thread);
211     // get and check this set
212     JSHandle<JSTaggedValue> self(GetThis(argv));
213     if (!self->IsJSAPITreeSet()) {
214         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeSet()) {
215             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
216         } else {
217             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
218                                                                 "The getLowerValue method cannot be bound");
219             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
220         }
221     }
222 
223     JSHandle<JSAPITreeSet> set = JSHandle<JSAPITreeSet>::Cast(self);
224     JSHandle<JSTaggedValue> key = GetCallArg(argv, 0);
225     JSHandle<TaggedTreeSet> tset(thread, set->GetTreeSet());
226     return TaggedTreeSet::GetLowerKey(thread, tset, key);
227 }
228 
GetHigherValue(EcmaRuntimeCallInfo * argv)229 JSTaggedValue ContainersTreeSet::GetHigherValue(EcmaRuntimeCallInfo *argv)
230 {
231     BUILTINS_API_TRACE(argv->GetThread(), TreeSet, GetHigherValue);
232     JSThread *thread = argv->GetThread();
233     [[maybe_unused]] EcmaHandleScope handleScope(thread);
234     // get and check this set
235     JSHandle<JSTaggedValue> self(GetThis(argv));
236     if (!self->IsJSAPITreeSet()) {
237         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeSet()) {
238             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
239         } else {
240             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
241                                                                 "The getHigherValue method cannot be bound");
242             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
243         }
244     }
245 
246     JSHandle<JSAPITreeSet> set = JSHandle<JSAPITreeSet>::Cast(self);
247     JSHandle<JSTaggedValue> key = GetCallArg(argv, 0);
248     JSHandle<TaggedTreeSet> tset(thread, set->GetTreeSet());
249     return TaggedTreeSet::GetHigherKey(thread, tset, key);
250 }
251 
PopFirst(EcmaRuntimeCallInfo * argv)252 JSTaggedValue ContainersTreeSet::PopFirst(EcmaRuntimeCallInfo *argv)
253 {
254     BUILTINS_API_TRACE(argv->GetThread(), TreeSet, PopFirst);
255     JSThread *thread = argv->GetThread();
256     [[maybe_unused]] EcmaHandleScope handleScope(thread);
257     // get and check this set
258     JSHandle<JSTaggedValue> self(GetThis(argv));
259     if (!self->IsJSAPITreeSet()) {
260         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeSet()) {
261             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
262         } else {
263             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
264                                                                 "The popFirst method cannot be bound");
265             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
266         }
267     }
268 
269     JSHandle<JSAPITreeSet> set = JSHandle<JSAPITreeSet>::Cast(self);
270     return JSAPITreeSet::PopFirst(thread, set);
271 }
272 
PopLast(EcmaRuntimeCallInfo * argv)273 JSTaggedValue ContainersTreeSet::PopLast(EcmaRuntimeCallInfo *argv)
274 {
275     BUILTINS_API_TRACE(argv->GetThread(), TreeSet, PopLast);
276     JSThread *thread = argv->GetThread();
277     [[maybe_unused]] EcmaHandleScope handleScope(thread);
278     // get and check this set
279     JSHandle<JSTaggedValue> self(GetThis(argv));
280     if (!self->IsJSAPITreeSet()) {
281         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeSet()) {
282             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
283         } else {
284             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
285                                                                 "The popLast method cannot be bound");
286             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
287         }
288     }
289 
290     JSHandle<JSAPITreeSet> set = JSHandle<JSAPITreeSet>::Cast(self);
291     return JSAPITreeSet::PopLast(thread, set);
292 }
293 
IsEmpty(EcmaRuntimeCallInfo * argv)294 JSTaggedValue ContainersTreeSet::IsEmpty(EcmaRuntimeCallInfo *argv)
295 {
296     BUILTINS_API_TRACE(argv->GetThread(), TreeSet, IsEmpty);
297     JSThread *thread = argv->GetThread();
298     [[maybe_unused]] EcmaHandleScope handleScope(thread);
299     // get and check this set
300     JSHandle<JSTaggedValue> self = GetThis(argv);
301     if (!self->IsJSAPITreeSet()) {
302         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeSet()) {
303             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
304         } else {
305             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
306                                                                 "The isEmpty method cannot be bound");
307             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
308         }
309     }
310     JSHandle<JSAPITreeSet> set = JSHandle<JSAPITreeSet>::Cast(self);
311     return GetTaggedBoolean(set->GetSize() == 0);
312 }
313 
Values(EcmaRuntimeCallInfo * argv)314 JSTaggedValue ContainersTreeSet::Values(EcmaRuntimeCallInfo *argv)
315 {
316     BUILTINS_API_TRACE(argv->GetThread(), TreeSet, Values);
317     JSThread *thread = argv->GetThread();
318     [[maybe_unused]] EcmaHandleScope handleScope(thread);
319     JSHandle<JSTaggedValue> self = GetThis(argv);
320     JSHandle<JSTaggedValue> iter = JSAPITreeSetIterator::CreateTreeSetIterator(thread, self, IterationKind::KEY);
321     return iter.GetTaggedValue();
322 }
323 
Entries(EcmaRuntimeCallInfo * argv)324 JSTaggedValue ContainersTreeSet::Entries(EcmaRuntimeCallInfo *argv)
325 {
326     BUILTINS_API_TRACE(argv->GetThread(), TreeSet, Entries);
327     JSThread *thread = argv->GetThread();
328     [[maybe_unused]] EcmaHandleScope handleScope(thread);
329     JSHandle<JSTaggedValue> self = GetThis(argv);
330     JSHandle<JSTaggedValue> iter =
331         JSAPITreeSetIterator::CreateTreeSetIterator(thread, self, IterationKind::KEY_AND_VALUE);
332     return iter.GetTaggedValue();
333 }
334 
ForEach(EcmaRuntimeCallInfo * argv)335 JSTaggedValue ContainersTreeSet::ForEach(EcmaRuntimeCallInfo *argv)
336 {
337     BUILTINS_API_TRACE(argv->GetThread(), TreeSet, ForEach);
338     JSThread *thread = argv->GetThread();
339     [[maybe_unused]] EcmaHandleScope handleScope(thread);
340     // get and check TreeSet object
341     JSHandle<JSTaggedValue> self = GetThis(argv);
342     if (!self->IsJSAPITreeSet()) {
343         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeSet()) {
344             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
345         } else {
346             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
347                                                                 "The forEach method cannot be bound");
348             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
349         }
350     }
351     // get and check callback function
352     JSHandle<JSTaggedValue> func(GetCallArg(argv, 0));
353     if (!func->IsCallable()) {
354         JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, func.GetTaggedValue());
355         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
356         CString errorMsg =
357             "The type of \"callbackfn\" must be callable. Received value is: " + ConvertToString(*result);
358         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
359         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
360     }
361     // If thisArg was supplied, let T be thisArg; else let T be undefined.
362     JSHandle<JSTaggedValue> thisArg = GetCallArg(argv, 1);
363     JSHandle<JSAPITreeSet> tset = JSHandle<JSAPITreeSet>::Cast(self);
364     JSMutableHandle<TaggedTreeSet> iteratedSet(thread, tset->GetTreeSet());
365     uint32_t elements = iteratedSet->NumberOfElements();
366     JSHandle<TaggedArray> entries = TaggedTreeSet::GetArrayFromSet(thread, iteratedSet);
367     uint32_t index = 0;
368     size_t length = entries->GetLength();
369     const uint32_t argsLength = 3;
370     JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
371     JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
372     while (index < elements) {
373         int entriesIndex = entries->Get(index).GetInt();
374         key.Update(iteratedSet->GetKey(entriesIndex));
375         // Let funcResult be Call(callbackfn, T, «e, e, S»).
376         EcmaRuntimeCallInfo *info = EcmaInterpreter::NewRuntimeCallInfo(thread, func, thisArg, undefined, argsLength);
377         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
378         info->SetCallArg(key.GetTaggedValue(), key.GetTaggedValue(), self.GetTaggedValue());
379         JSTaggedValue ret = JSFunction::Call(info);
380         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ret);
381         // check entries should be update, size will be update by set add and remove.
382         if (tset->GetSize() != static_cast<int>(length)) {
383             iteratedSet.Update(tset->GetTreeSet());
384             entries = TaggedTreeSet::GetArrayFromSet(thread, iteratedSet);
385             elements = iteratedSet->NumberOfElements();
386             length = entries->GetLength();
387         }
388         index++;
389     }
390     return JSTaggedValue::Undefined();
391 }
392 
GetLength(EcmaRuntimeCallInfo * argv)393 JSTaggedValue ContainersTreeSet::GetLength(EcmaRuntimeCallInfo *argv)
394 {
395     ASSERT(argv);
396     BUILTINS_API_TRACE(argv->GetThread(), TreeSet, GetLength);
397     JSThread *thread = argv->GetThread();
398     [[maybe_unused]] EcmaHandleScope handleScope(thread);
399     // get and check this set
400     JSHandle<JSTaggedValue> self(GetThis(argv));
401     if (!self->IsJSAPITreeSet()) {
402         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeSet()) {
403             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
404         } else {
405             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
406                                                                 "The getLength method cannot be bound");
407             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
408         }
409     }
410 
411     int count = JSHandle<JSAPITreeSet>::Cast(self)->GetSize();
412     return JSTaggedValue(count);
413 }
414 }  // namespace panda::ecmascript::containers
415