1 /*
2 * Copyright (c) 2021 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 #ifndef ECMASCRIPT_JSOBJECT_INL_H
17 #define ECMASCRIPT_JSOBJECT_INL_H
18
19 #include "ecmascript/js_object.h"
20
21 #include "ecmascript/js_array.h"
22 #include "ecmascript/js_hclass-inl.h"
23 #include "ecmascript/js_tagged_value-inl.h"
24 #include "ecmascript/js_typed_array.h"
25 #include "ecmascript/tagged_array-inl.h"
26
27 namespace panda::ecmascript {
SetCallable(bool flag)28 inline void ECMAObject::SetCallable(bool flag)
29 {
30 GetClass()->SetCallable(flag);
31 }
32
IsCallable()33 inline bool ECMAObject::IsCallable() const
34 {
35 return GetClass()->IsCallable();
36 }
37
38 // JSObject
IsExtensible()39 inline bool JSObject::IsExtensible() const
40 {
41 return GetJSHClass()->IsExtensible();
42 }
43
FillElementsWithHoles(const JSThread * thread,uint32_t start,uint32_t end)44 inline void JSObject::FillElementsWithHoles(const JSThread *thread, uint32_t start, uint32_t end)
45 {
46 if (start >= end) {
47 return;
48 }
49
50 TaggedArray *elements = TaggedArray::Cast(GetElements().GetTaggedObject());
51 for (uint32_t i = start; i < end; i++) {
52 elements->Set(thread, i, JSTaggedValue::Hole());
53 }
54 }
55
GetJSHClass()56 inline JSHClass *JSObject::GetJSHClass() const
57 {
58 return GetClass();
59 }
60
IsJSGlobalObject()61 inline bool JSObject::IsJSGlobalObject() const
62 {
63 return GetJSHClass()->IsJSGlobalObject();
64 }
65
IsConstructor()66 inline bool JSObject::IsConstructor() const
67 {
68 return GetJSHClass()->IsConstructor();
69 }
70
IsECMAObject()71 inline bool JSObject::IsECMAObject() const
72 {
73 return GetJSHClass()->IsECMAObject();
74 }
75
IsJSError()76 inline bool JSObject::IsJSError() const
77 {
78 return GetJSHClass()->IsJSError();
79 }
80
IsArguments()81 inline bool JSObject::IsArguments() const
82 {
83 return GetJSHClass()->IsArguments();
84 }
85
IsDate()86 inline bool JSObject::IsDate() const
87 {
88 return GetJSHClass()->IsDate();
89 }
90
IsJSArray()91 inline bool JSObject::IsJSArray() const
92 {
93 return GetJSHClass()->IsJSArray();
94 }
95
IsJSMap()96 inline bool JSObject::IsJSMap() const
97 {
98 return GetJSHClass()->IsJSMap();
99 }
100
IsJSSet()101 inline bool JSObject::IsJSSet() const
102 {
103 return GetJSHClass()->IsJSSet();
104 }
105
IsJSRegExp()106 inline bool JSObject::IsJSRegExp() const
107 {
108 return GetJSHClass()->IsJSRegExp();
109 }
110
IsJSFunction()111 inline bool JSObject::IsJSFunction() const
112 {
113 return GetJSHClass()->IsJSFunction();
114 }
115
IsBoundFunction()116 inline bool JSObject::IsBoundFunction() const
117 {
118 return GetJSHClass()->IsJsBoundFunction();
119 }
120
IsJSIntlBoundFunction()121 inline bool JSObject::IsJSIntlBoundFunction() const
122 {
123 return GetJSHClass()->IsJSIntlBoundFunction();
124 }
125
IsProxyRevocFunction()126 inline bool JSObject::IsProxyRevocFunction() const
127 {
128 return GetJSHClass()->IsJSProxyRevocFunction();
129 }
130
IsAccessorData()131 inline bool JSObject::IsAccessorData() const
132 {
133 return GetJSHClass()->IsAccessorData();
134 }
135
IsJSGlobalEnv()136 inline bool JSObject::IsJSGlobalEnv() const
137 {
138 return GetJSHClass()->IsJsGlobalEnv();
139 }
140
IsJSProxy()141 inline bool JSObject::IsJSProxy() const
142 {
143 return GetJSHClass()->IsJSProxy();
144 }
145
IsGeneratorObject()146 inline bool JSObject::IsGeneratorObject() const
147 {
148 return GetJSHClass()->IsGeneratorObject();
149 }
150
IsAsyncGeneratorObject()151 inline bool JSObject::IsAsyncGeneratorObject() const
152 {
153 return GetJSHClass()->IsAsyncGeneratorObject();
154 }
155
IsForinIterator()156 inline bool JSObject::IsForinIterator() const
157 {
158 return GetJSHClass()->IsForinIterator();
159 }
160
IsJSSetIterator()161 inline bool JSObject::IsJSSetIterator() const
162 {
163 return GetJSHClass()->IsJSSetIterator();
164 }
165
IsJSRegExpIterator()166 inline bool JSObject::IsJSRegExpIterator() const
167 {
168 return GetJSHClass()->IsJSRegExpIterator();
169 }
170
IsJSMapIterator()171 inline bool JSObject::IsJSMapIterator() const
172 {
173 return GetJSHClass()->IsJSMapIterator();
174 }
175
IsJSArrayIterator()176 inline bool JSObject::IsJSArrayIterator() const
177 {
178 return GetJSHClass()->IsJSArrayIterator();
179 }
180
IsJSAPIArrayListIterator()181 inline bool JSObject::IsJSAPIArrayListIterator() const
182 {
183 return GetJSHClass()->IsJSAPIArrayListIterator();
184 }
185
IsJSAPIStackIterator()186 inline bool JSObject::IsJSAPIStackIterator() const
187 {
188 return GetJSHClass()->IsJSAPIStackIterator();
189 }
190
IsJSAPIVectorIterator()191 inline bool JSObject::IsJSAPIVectorIterator() const
192 {
193 return GetJSHClass()->IsJSAPIVectorIterator();
194 }
195
IsJSAPILinkedListIterator()196 inline bool JSObject::IsJSAPILinkedListIterator() const
197 {
198 return GetJSHClass()->IsJSAPILinkedListIterator();
199 }
200
IsJSAPIListIterator()201 inline bool JSObject::IsJSAPIListIterator() const
202 {
203 return GetJSHClass()->IsJSAPIListIterator();
204 }
205
IsJSPrimitiveRef()206 inline bool JSObject::IsJSPrimitiveRef() const
207 {
208 return GetJSHClass()->IsJsPrimitiveRef();
209 }
210
IsElementDict()211 inline bool JSObject::IsElementDict() const
212 {
213 return TaggedArray::Cast(GetElements().GetTaggedObject())->IsDictionaryMode();
214 }
215
IsPropertiesDict()216 inline bool JSObject::IsPropertiesDict() const
217 {
218 return TaggedArray::Cast(GetProperties().GetTaggedObject())->IsDictionaryMode();
219 }
220
IsTypedArray()221 inline bool JSObject::IsTypedArray() const
222 {
223 return GetJSHClass()->IsTypedArray();
224 }
225
SetPropertyInlinedProps(const JSThread * thread,uint32_t index,JSTaggedValue value)226 void JSObject::SetPropertyInlinedProps(const JSThread *thread, uint32_t index, JSTaggedValue value)
227 {
228 SetPropertyInlinedProps(thread, GetJSHClass(), index, value);
229 }
230
GetPropertyInlinedProps(uint32_t index)231 JSTaggedValue JSObject::GetPropertyInlinedProps(uint32_t index) const
232 {
233 return GetPropertyInlinedProps(GetJSHClass(), index);
234 }
235
SetPropertyInlinedProps(const JSThread * thread,const JSHClass * hclass,uint32_t index,JSTaggedValue value)236 void JSObject::SetPropertyInlinedProps(const JSThread *thread, const JSHClass *hclass, uint32_t index,
237 JSTaggedValue value)
238 {
239 uint32_t offset = hclass->GetInlinedPropertiesOffset(index);
240 SET_VALUE_WITH_BARRIER(thread, this, offset, value);
241 }
242
GetPropertyInlinedProps(const JSHClass * hclass,uint32_t index)243 JSTaggedValue JSObject::GetPropertyInlinedProps(const JSHClass *hclass, uint32_t index) const
244 {
245 uint32_t offset = hclass->GetInlinedPropertiesOffset(index);
246 return JSTaggedValue(GET_VALUE(this, offset));
247 }
248
GetProperty(const JSHClass * hclass,PropertyAttributes attr)249 JSTaggedValue JSObject::GetProperty(const JSHClass *hclass, PropertyAttributes attr) const
250 {
251 if (attr.IsInlinedProps()) {
252 return GetPropertyInlinedProps(hclass, attr.GetOffset());
253 }
254 TaggedArray *array = TaggedArray::Cast(GetProperties().GetTaggedObject());
255 return array->Get(attr.GetOffset() - hclass->GetInlinedProperties());
256 }
257
SetProperty(const JSThread * thread,const JSHClass * hclass,PropertyAttributes attr,JSTaggedValue value)258 void JSObject::SetProperty(const JSThread *thread, const JSHClass *hclass, PropertyAttributes attr, JSTaggedValue value)
259 {
260 if (attr.IsInlinedProps()) {
261 SetPropertyInlinedProps(thread, hclass, attr.GetOffset(), value);
262 } else {
263 TaggedArray *array = TaggedArray::Cast(GetProperties().GetTaggedObject());
264 array->Set(thread, attr.GetOffset() - hclass->GetInlinedProperties(), value);
265 }
266 }
267
ShouldTransToDict(uint32_t capacity,uint32_t index)268 inline bool JSObject::ShouldTransToDict(uint32_t capacity, uint32_t index)
269 {
270 if (index < capacity) {
271 return false;
272 }
273 if (index - capacity > MAX_GAP) {
274 return true;
275 }
276
277 if (capacity >= MIN_GAP) {
278 return index > capacity * FAST_ELEMENTS_FACTOR;
279 }
280
281 return false;
282 }
283
ComputeElementCapacity(uint32_t oldCapacity)284 inline uint32_t JSObject::ComputeElementCapacity(uint32_t oldCapacity)
285 {
286 uint32_t newCapacity = oldCapacity + (oldCapacity >> 1U);
287 return newCapacity > MIN_ELEMENTS_LENGTH ? newCapacity : MIN_ELEMENTS_LENGTH;
288 }
289
ComputePropertyCapacity(uint32_t oldCapacity)290 inline uint32_t JSObject::ComputePropertyCapacity(uint32_t oldCapacity)
291 {
292 uint32_t newCapacity = static_cast<uint32_t>(oldCapacity + PROPERTIES_GROW_SIZE);
293 return newCapacity > JSHClass::MAX_CAPACITY_OF_OUT_OBJECTS ? JSHClass::MAX_CAPACITY_OF_OUT_OBJECTS
294 : newCapacity;
295 }
296
297 // static
298 template<ElementTypes types>
CreateListFromArrayLike(JSThread * thread,const JSHandle<JSTaggedValue> & obj)299 JSHandle<JSTaggedValue> JSObject::CreateListFromArrayLike(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
300 {
301 // 3. If Type(obj) is not Object, throw a TypeError exception.
302 if (!obj->IsECMAObject()) {
303 THROW_TYPE_ERROR_AND_RETURN(thread, "CreateListFromArrayLike must accept object",
304 JSHandle<JSTaggedValue>(thread, JSTaggedValue::Exception()));
305 }
306 // 4. Let len be ToLength(Get(obj, "length")).
307 JSHandle<JSTaggedValue> lengthKeyHandle = thread->GlobalConstants()->GetHandledLengthString();
308
309 JSHandle<JSTaggedValue> value = GetProperty(thread, obj, lengthKeyHandle).GetValue();
310 JSTaggedNumber number = JSTaggedValue::ToLength(thread, value);
311 // 5. ReturnIfAbrupt(len).
312 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
313 if (number.GetNumber() > MAX_ELEMENT_INDEX) {
314 THROW_TYPE_ERROR_AND_RETURN(thread, "len is bigger than 2^32 - 1",
315 JSHandle<JSTaggedValue>(thread, JSTaggedValue::Exception()));
316 }
317
318 uint32_t len = number.ToUint32();
319 // 6. Let list be an empty List.
320 JSHandle<TaggedArray> array = thread->GetEcmaVM()->GetFactory()->NewTaggedArray(len);
321
322 if (obj->IsTypedArray()) {
323 JSTypedArray::FastCopyElementToArray(thread, obj, array);
324 // c. ReturnIfAbrupt(next).
325 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
326 return JSHandle<JSTaggedValue>(array);
327 }
328 // 8. Repeat while index < len
329 for (uint32_t i = 0; i < len; i++) {
330 JSTaggedValue next = JSTaggedValue::GetProperty(thread, obj, i).GetValue().GetTaggedValue();
331 // c. ReturnIfAbrupt(next).
332 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
333
334 if constexpr (types == ElementTypes::STRING_AND_SYMBOL) {
335 if (!next.IsString() && !next.IsSymbol()) {
336 THROW_TYPE_ERROR_AND_RETURN(thread, "CreateListFromArrayLike: not an element of elementTypes",
337 JSHandle<JSTaggedValue>(thread, JSTaggedValue::Exception()));
338 }
339 }
340
341 array->Set(thread, i, next);
342 }
343 return JSHandle<JSTaggedValue>(array);
344 }
345
ShouldGetValueFromBox(ObjectOperator * op)346 inline JSTaggedValue JSObject::ShouldGetValueFromBox(ObjectOperator *op)
347 {
348 JSTaggedValue result = op->GetValue();
349 if (result.IsPropertyBox()) {
350 result = PropertyBox::Cast(result.GetTaggedObject())->GetValue();
351 }
352 return result;
353 }
354
CheckHClassHit(const JSHandle<JSObject> & obj,const JSHandle<JSHClass> & cls)355 inline bool JSObject::CheckHClassHit(const JSHandle<JSObject> &obj, const JSHandle<JSHClass> &cls)
356 {
357 return obj->GetJSHClass() == *cls;
358 }
359
SetValuesOrEntries(JSThread * thread,const JSHandle<TaggedArray> & prop,uint32_t index,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value,PropertyKind kind)360 inline uint32_t JSObject::SetValuesOrEntries(JSThread *thread, const JSHandle<TaggedArray> &prop, uint32_t index,
361 const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &value,
362 PropertyKind kind)
363 {
364 if (kind == PropertyKind::VALUE) {
365 prop->Set(thread, index++, value);
366 return index;
367 }
368 JSHandle<TaggedArray> keyValue = thread->GetEcmaVM()->GetFactory()->NewTaggedArray(2); // 2: key-value pair
369 keyValue->Set(thread, 0, key);
370 keyValue->Set(thread, 1, value);
371 JSHandle<JSArray> entry = JSArray::CreateArrayFromList(thread, keyValue);
372 prop->Set(thread, index++, entry.GetTaggedValue());
373 return index;
374 }
375
GetOwnEnumerableNamesInFastMode(JSThread * thread,const JSHandle<JSObject> & obj,uint32_t * copyLengthOfKeys,uint32_t * copyLengthOfElements)376 inline std::pair<JSHandle<TaggedArray>, JSHandle<TaggedArray>> JSObject::GetOwnEnumerableNamesInFastMode(
377 JSThread *thread, const JSHandle<JSObject> &obj, uint32_t *copyLengthOfKeys, uint32_t *copyLengthOfElements)
378 {
379 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
380 uint32_t numOfKeys = obj->GetNumberOfKeys();
381 uint32_t numOfElements = obj->GetNumberOfElements();
382 JSHandle<TaggedArray> elementArray = numOfElements > 0 ? JSObject::GetEnumElementKeys(
383 thread, obj, 0, numOfElements, copyLengthOfElements) : factory->EmptyArray();
384 JSHandle<TaggedArray> keyArray = numOfKeys > 0 ? JSObject::GetAllEnumKeys(
385 thread, obj, 0, numOfKeys, copyLengthOfKeys) : factory->EmptyArray();
386 return std::make_pair(keyArray, elementArray);
387 }
388 } // namespace panda::ecmascript
389 #endif // ECMASCRIPT_JSOBJECT_INL_H
390