• 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/js_api/js_api_stack.h"
17 
18 #include "ecmascript/containers/containers_errors.h"
19 #include "ecmascript/object_factory-inl.h"
20 
21 namespace panda::ecmascript {
22 using ContainerError = containers::ContainerError;
23 using ErrorFlag = containers::ErrorFlag;
Empty()24 bool JSAPIStack::Empty()
25 {
26     if (this->GetTop() == -1) {
27         return true;
28     }
29     return false;
30 }
31 
Push(JSThread * thread,const JSHandle<JSAPIStack> & stack,const JSHandle<JSTaggedValue> & value)32 JSTaggedValue JSAPIStack::Push(JSThread *thread, const JSHandle<JSAPIStack> &stack,
33                                const JSHandle<JSTaggedValue> &value)
34 {
35     int top = static_cast<int>(stack->GetTop());
36     JSHandle<TaggedArray> elements = GrowCapacity(thread, stack, top + 1);
37 
38     ASSERT(!elements->IsDictionaryMode());
39     elements->Set(thread, top + 1, value);
40     stack->SetTop(++top);
41     return value.GetTaggedValue();
42 }
43 
Peek()44 JSTaggedValue JSAPIStack::Peek()
45 {
46     int top = this->GetTop();
47     if (top == -1) {
48         return JSTaggedValue::Undefined();
49     }
50 
51     TaggedArray *elements = TaggedArray::Cast(this->GetElements().GetTaggedObject());
52     ASSERT(!elements->IsDictionaryMode());
53     return elements->Get(top);
54 }
55 
Pop(JSThread * thread)56 JSTaggedValue JSAPIStack::Pop(JSThread *thread)
57 {
58     int top = this->GetTop();
59     if (top == -1) {
60         return JSTaggedValue::Undefined();
61     }
62     JSHandle<TaggedArray> elements(thread, TaggedArray::Cast(this->GetElements().GetTaggedObject()));
63     ASSERT(!elements->IsDictionaryMode());
64     JSTaggedValue ret = elements->Get(top);
65     elements->Set(thread, top, JSTaggedValue::Hole());
66     this->SetTop(--top);
67     return ret;
68 }
69 
Search(const JSHandle<JSTaggedValue> & value)70 int JSAPIStack::Search(const JSHandle<JSTaggedValue> &value)
71 {
72     int top = this->GetTop();
73     TaggedArray *elements = TaggedArray::Cast(this->GetElements().GetTaggedObject());
74     ASSERT(!elements->IsDictionaryMode());
75     for (int i = 0; i <= top; i++) {
76         if (value.GetTaggedValue() == elements->Get(i)) {
77             return i;
78         }
79     }
80     return -1;
81 }
82 
GrowCapacity(const JSThread * thread,const JSHandle<JSAPIStack> & obj,uint32_t capacity)83 JSHandle<TaggedArray> JSAPIStack::GrowCapacity(const JSThread *thread, const JSHandle<JSAPIStack> &obj,
84                                                uint32_t capacity)
85 {
86     JSHandle<TaggedArray> oldElements(thread, obj->GetElements());
87     uint32_t oldLength = oldElements->GetLength();
88     if (capacity < oldLength) {
89         return oldElements;
90     }
91     uint32_t newCapacity = ComputeCapacity(capacity);
92     JSHandle<TaggedArray> newElements =
93         thread->GetEcmaVM()->GetFactory()->CopyArray(oldElements, oldLength, newCapacity);
94 
95     obj->SetElements(thread, newElements);
96     return newElements;
97 }
98 
99 
Get(const uint32_t index)100 JSTaggedValue JSAPIStack::Get(const uint32_t index)
101 {
102     ASSERT(static_cast<int>(index) <= GetTop());
103     TaggedArray *elements = TaggedArray::Cast(GetElements().GetTaggedObject());
104     return elements->Get(index);
105 }
106 
Set(JSThread * thread,const uint32_t index,JSTaggedValue value)107 JSTaggedValue JSAPIStack::Set(JSThread *thread, const uint32_t index, JSTaggedValue value)
108 {
109     uint32_t length = GetSize() + 1;
110     if (index >= length) {
111         return JSTaggedValue::Undefined();
112     }
113     TaggedArray *elements = TaggedArray::Cast(GetElements().GetTaggedObject());
114     elements->Set(thread, index, value);
115     return JSTaggedValue::Undefined();
116 }
117 
Has(JSTaggedValue value) const118 bool JSAPIStack::Has(JSTaggedValue value) const
119 {
120     TaggedArray *elements = TaggedArray::Cast(GetElements().GetTaggedObject());
121     int top = static_cast<int>(GetTop());
122     if (top == -1) {
123         return false;
124     }
125 
126     for (int i = 0; i < top + 1; i++) {
127         if (JSTaggedValue::SameValue(elements->Get(i), value)) {
128             return true;
129         }
130     }
131     return false;
132 }
133 
OwnKeys(JSThread * thread,const JSHandle<JSAPIStack> & obj)134 JSHandle<TaggedArray> JSAPIStack::OwnKeys(JSThread *thread, const JSHandle<JSAPIStack> &obj)
135 {
136     return JSObject::GetOwnPropertyKeys(thread, JSHandle<JSObject>::Cast(obj));
137 }
138 
OwnEnumKeys(JSThread * thread,const JSHandle<JSAPIStack> & obj)139 JSHandle<TaggedArray> JSAPIStack::OwnEnumKeys(JSThread *thread, const JSHandle<JSAPIStack> &obj)
140 {
141     return JSObject::GetOwnEnumPropertyKeys(thread, JSHandle<JSObject>::Cast(obj));
142 }
143 
GetOwnProperty(JSThread * thread,const JSHandle<JSAPIStack> & obj,const JSHandle<JSTaggedValue> & key)144 bool JSAPIStack::GetOwnProperty(JSThread *thread, const JSHandle<JSAPIStack> &obj,
145                                 const JSHandle<JSTaggedValue> &key)
146 {
147     uint32_t index = 0;
148     if (UNLIKELY(!JSTaggedValue::ToElementIndex(key.GetTaggedValue(), &index))) {
149         JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, key.GetTaggedValue());
150         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
151         CString errorMsg =
152             "The type of \"index\" can not obtain attributes of no-number type. Received value is: "
153             + ConvertToString(*result);
154         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
155         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, false);
156     }
157 
158     uint32_t length = static_cast<uint32_t>(obj->GetTop() + 1);
159     if (length == 0) {
160         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, "Container is empty");
161         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, false);
162     }
163     if (index >= length) {
164         std::ostringstream oss;
165         ASSERT(length > 0);
166         oss << "The value of \"index\" is out of range. It must be > " << (length - 1)
167             << ". Received value is: " << index;
168         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
169         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, false);
170     }
171 
172     obj->Get(index);
173     return true;
174 }
175 
GetProperty(JSThread * thread,const JSHandle<JSAPIStack> & obj,const JSHandle<JSTaggedValue> & key)176 OperationResult JSAPIStack::GetProperty(JSThread *thread, const JSHandle<JSAPIStack> &obj,
177                                         const JSHandle<JSTaggedValue> &key)
178 {
179     int length = obj->GetTop() + 1;
180     if (length == 0) {
181         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, "Container is empty");
182         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, OperationResult(thread,
183                                                                         JSTaggedValue::Exception(),
184                                                                         PropertyMetaData(false)));
185     }
186     JSHandle<JSTaggedValue> indexKey = key;
187     if (indexKey->IsDouble()) {
188         // Math.floor(1) will produce TaggedDouble, we need to cast into TaggedInt
189         // For integer which is greater than INT32_MAX, it will remain TaggedDouble
190         indexKey = JSHandle<JSTaggedValue>(thread, JSTaggedValue::TryCastDoubleToInt32(indexKey->GetDouble()));
191     }
192     if (!indexKey->IsInt()) {
193         CString errorMsg = "The type of \"index\" must be small integer.";
194         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
195         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error,
196                                          OperationResult(thread, JSTaggedValue::Exception(), PropertyMetaData(false)));
197     }
198 
199     int index = indexKey->GetInt();
200     if (index < 0 || index >= length) {
201         std::ostringstream oss;
202         oss << "The value of \"index\" is out of range. It must be >= 0 && <= " << (length - 1)
203             << ". Received value is: " << index;
204         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
205         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, OperationResult(thread,
206                                                                         JSTaggedValue::Exception(),
207                                                                         PropertyMetaData(false)));
208     }
209 
210     return OperationResult(thread, obj->Get(index), PropertyMetaData(false));
211 }
212 
SetProperty(JSThread * thread,const JSHandle<JSAPIStack> & obj,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value)213 bool JSAPIStack::SetProperty(JSThread *thread, const JSHandle<JSAPIStack> &obj,
214                              const JSHandle<JSTaggedValue> &key,
215                              const JSHandle<JSTaggedValue> &value)
216 {
217     int length = obj->GetTop() + 1;
218     JSHandle<JSTaggedValue> indexKey = key;
219     if (indexKey->IsDouble()) {
220         // Math.floor(1) will produce TaggedDouble, we need to cast into TaggedInt
221         // For integer which is greater than INT32_MAX, it will remain TaggedDouble
222         indexKey = JSHandle<JSTaggedValue>(thread, JSTaggedValue::TryCastDoubleToInt32(indexKey->GetDouble()));
223     }
224     if (!indexKey->IsInt()) {
225         return false;
226     }
227 
228     int index = indexKey->GetInt();
229     if (index < 0 || index >= length) {
230         return false;
231     }
232 
233     obj->Set(thread, index, value.GetTaggedValue());
234     return true;
235 }
236 }  // namespace panda::ecmascript
237