• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 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_stack.h"
17 
18 #include "ecmascript/containers/containers_errors.h"
19 #include "ecmascript/ecma_vm.h"
20 #include "ecmascript/interpreter/interpreter.h"
21 #include "ecmascript/js_api/js_api_stack.h"
22 #include "ecmascript/js_api/js_api_stack_iterator.h"
23 #include "ecmascript/js_function.h"
24 #include "ecmascript/js_iterator.h"
25 #include "ecmascript/object_factory.h"
26 #include "ecmascript/tagged_array-inl.h"
27 
28 namespace panda::ecmascript::containers {
StackConstructor(EcmaRuntimeCallInfo * argv)29 JSTaggedValue ContainersStack::StackConstructor(EcmaRuntimeCallInfo *argv)
30 {
31     ASSERT(argv != nullptr);
32     BUILTINS_API_TRACE(argv->GetThread(), Stack, Constructor);
33     JSThread *thread = argv->GetThread();
34     [[maybe_unused]] EcmaHandleScope handleScope(thread);
35     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
36     JSHandle<JSTaggedValue> newTarget = GetNewTarget(argv);
37     if (newTarget->IsUndefined()) {
38         JSTaggedValue error =
39             ContainerError::BusinessError(thread, ErrorFlag::IS_NULL_ERROR,
40                                           "The List's constructor cannot be directly invoked");
41         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
42     }
43     JSHandle<JSTaggedValue> constructor = GetConstructor(argv);
44     JSHandle<JSObject> obj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(constructor), newTarget);
45     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
46 
47     JSHandle<JSAPIStack> stack = JSHandle<JSAPIStack>::Cast(obj);
48     stack->SetTop(-1);
49 
50     return obj.GetTaggedValue();
51 }
52 
IsEmpty(EcmaRuntimeCallInfo * argv)53 JSTaggedValue ContainersStack::IsEmpty(EcmaRuntimeCallInfo *argv)
54 {
55     ASSERT(argv != nullptr);
56     BUILTINS_API_TRACE(argv->GetThread(), Stack, IsEmpty);
57     JSThread *thread = argv->GetThread();
58     [[maybe_unused]] EcmaHandleScope handleScope(thread);
59     JSHandle<JSTaggedValue> self = GetThis(argv);
60 
61     if (!self->IsJSAPIStack()) {
62         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIStack()) {
63             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
64         } else {
65             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
66                                                                 "The isEmpty method cannot be bound");
67             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
68         }
69     }
70     JSHandle<JSAPIStack> stack = JSHandle<JSAPIStack>::Cast(self);
71     bool judge = stack->Empty();
72 
73     return GetTaggedBoolean(judge);
74 }
75 
Push(EcmaRuntimeCallInfo * argv)76 JSTaggedValue ContainersStack::Push(EcmaRuntimeCallInfo *argv)
77 {
78     ASSERT(argv != nullptr);
79     BUILTINS_API_TRACE(argv->GetThread(), Stack, Push);
80     JSThread *thread = argv->GetThread();
81     [[maybe_unused]] EcmaHandleScope handleScope(thread);
82     JSHandle<JSTaggedValue> self = GetThis(argv);
83 
84     if (!self->IsJSAPIStack()) {
85         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIStack()) {
86             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
87         } else {
88             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
89                                                                 "The push method cannot be bound");
90             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
91         }
92     }
93 
94     JSHandle<JSTaggedValue> value = GetCallArg(argv, 0);
95     JSTaggedValue jsValue = JSAPIStack::Push(thread, JSHandle<JSAPIStack>::Cast(self), value);
96     return jsValue;
97 }
98 
Peek(EcmaRuntimeCallInfo * argv)99 JSTaggedValue ContainersStack::Peek(EcmaRuntimeCallInfo *argv)
100 {
101     ASSERT(argv != nullptr);
102     BUILTINS_API_TRACE(argv->GetThread(), Stack, Peek);
103     JSThread *thread = argv->GetThread();
104     [[maybe_unused]] EcmaHandleScope handleScope(thread);
105     JSHandle<JSTaggedValue> self = GetThis(argv);
106 
107     if (!self->IsJSAPIStack()) {
108         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIStack()) {
109             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
110         } else {
111             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
112                                                                 "The peek method cannot be bound");
113             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
114         }
115     }
116 
117     JSHandle<JSAPIStack> stack = JSHandle<JSAPIStack>::Cast(self);
118     JSTaggedValue jsValue = stack->Peek();
119     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
120     return jsValue;
121 }
122 
Locate(EcmaRuntimeCallInfo * argv)123 JSTaggedValue ContainersStack::Locate(EcmaRuntimeCallInfo *argv)
124 {
125     ASSERT(argv != nullptr);
126     BUILTINS_API_TRACE(argv->GetThread(), Stack, Locate);
127     JSThread *thread = argv->GetThread();
128     [[maybe_unused]] EcmaHandleScope handleScope(thread);
129     JSHandle<JSTaggedValue> self = GetThis(argv);
130 
131     if (!self->IsJSAPIStack()) {
132         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIStack()) {
133             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
134         } else {
135             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
136                                                                 "The locate method cannot be bound");
137             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
138         }
139     }
140 
141     JSHandle<JSTaggedValue> value = GetCallArg(argv, 0);
142     JSHandle<JSAPIStack> stack = JSHandle<JSAPIStack>::Cast(self);
143     int num = stack->Search(value);
144     return JSTaggedValue(num);
145 }
146 
Pop(EcmaRuntimeCallInfo * argv)147 JSTaggedValue ContainersStack::Pop(EcmaRuntimeCallInfo *argv)
148 {
149     ASSERT(argv != nullptr);
150     BUILTINS_API_TRACE(argv->GetThread(), Stack, Pop);
151     JSThread *thread = argv->GetThread();
152     [[maybe_unused]] EcmaHandleScope handleScope(thread);
153     JSHandle<JSTaggedValue> self = GetThis(argv);
154 
155     if (!self->IsJSAPIStack()) {
156         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIStack()) {
157             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
158         } else {
159             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
160                                                                 "The pop method cannot be bound");
161             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
162         }
163     }
164 
165     JSHandle<JSAPIStack> stack = JSHandle<JSAPIStack>::Cast(self);
166     JSTaggedValue jsValue = stack->Pop();
167     return jsValue;
168 }
169 
ForEach(EcmaRuntimeCallInfo * argv)170 JSTaggedValue ContainersStack::ForEach(EcmaRuntimeCallInfo *argv)
171 {
172     ASSERT(argv != nullptr);
173     BUILTINS_API_TRACE(argv->GetThread(), Stack, ForEach);
174     JSThread *thread = argv->GetThread();
175     [[maybe_unused]] EcmaHandleScope handleScope(thread);
176 
177     JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
178     if (!thisHandle->IsJSAPIStack()) {
179         if (thisHandle->IsJSProxy() && JSHandle<JSProxy>::Cast(thisHandle)->GetTarget().IsJSAPIStack()) {
180             thisHandle = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(thisHandle)->GetTarget());
181         } else {
182             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
183                                                                 "The forEach method cannot be bound");
184             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
185         }
186     }
187 
188     JSHandle<JSAPIStack> stack = JSHandle<JSAPIStack>::Cast(thisHandle);
189     uint32_t len = stack->GetSize();
190     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
191 
192     JSHandle<JSTaggedValue> callbackFnHandle = GetCallArg(argv, 0);
193     if (!callbackFnHandle->IsCallable()) {
194         JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, callbackFnHandle.GetTaggedValue());
195         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
196         CString errorMsg =
197             "The type of \"callbackfn\" must be callable. Received value is: " + ConvertToString(*result);
198         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
199         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
200     }
201 
202     JSHandle<JSTaggedValue> thisArgHandle = GetCallArg(argv, 1);
203     JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
204     uint32_t k = 0;
205     while (k < len + 1) {
206         JSTaggedValue kValue = stack->Get(k);
207         EcmaRuntimeCallInfo *info =
208             EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, undefined, 3); // 3:three args
209         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
210         info->SetCallArg(kValue, JSTaggedValue(k), thisHandle.GetTaggedValue());
211         JSTaggedValue funcResult = JSFunction::Call(info);
212         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, funcResult);
213         k++;
214     }
215     return JSTaggedValue::Undefined();
216 }
217 
Iterator(EcmaRuntimeCallInfo * argv)218 JSTaggedValue ContainersStack::Iterator(EcmaRuntimeCallInfo *argv)
219 {
220     ASSERT(argv != nullptr);
221     BUILTINS_API_TRACE(argv->GetThread(), Stack, Iterator);
222     JSThread *thread = argv->GetThread();
223     [[maybe_unused]] EcmaHandleScope handleScope(thread);
224     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
225     JSHandle<JSTaggedValue> self = GetThis(argv);
226     if (!self->IsJSAPIStack()) {
227         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIStack()) {
228             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
229         } else {
230             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
231                                                                 "The Symbol.iterator method cannot be bound");
232             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
233         }
234     }
235     JSHandle<JSAPIStackIterator> iter(factory->NewJSAPIStackIterator(JSHandle<JSAPIStack>::Cast(self)));
236     return iter.GetTaggedValue();
237 }
238 
GetLength(EcmaRuntimeCallInfo * argv)239 JSTaggedValue ContainersStack::GetLength(EcmaRuntimeCallInfo *argv)
240 {
241     ASSERT(argv != nullptr);
242     BUILTINS_API_TRACE(argv->GetThread(), Stack, GetLength);
243     JSThread *thread = argv->GetThread();
244     [[maybe_unused]] EcmaHandleScope handleScope(thread);
245     JSHandle<JSTaggedValue> self = GetThis(argv);
246 
247     if (!self->IsJSAPIStack()) {
248         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIStack()) {
249             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
250         } else {
251             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
252                                                                 "The getLength method cannot be bound");
253             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
254         }
255     }
256 
257     uint32_t len = (JSHandle<JSAPIStack>::Cast(self))->GetSize();
258     return JSTaggedValue(len + 1);
259 }
260 }  // namespace panda::ecmascript::containers
261