• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
ConvertValueWithRep(uint32_t index,JSTaggedValue value)226 std::pair<bool, JSTaggedValue> JSObject::ConvertValueWithRep(uint32_t index, JSTaggedValue value)
227 {
228     auto layout = LayoutInfo::Cast(GetJSHClass()->GetLayout().GetTaggedObject());
229     auto attr = layout->GetAttr(index);
230     if (attr.IsDoubleRep()) {
231         if (value.IsInt()) {
232             double doubleValue = value.GetInt();
233             return std::pair(true, JSTaggedValue(bit_cast<JSTaggedType>(doubleValue)));
234         } else if (value.IsDouble()) {
235             return std::pair(true, JSTaggedValue(bit_cast<JSTaggedType>(value.GetDouble())));
236         } else {
237             return std::pair(false, value);
238         }
239     } else if (attr.IsIntRep()) {
240         if (value.IsInt()) {
241             int intValue = value.GetInt();
242             return std::pair(true, JSTaggedValue(static_cast<JSTaggedType>(intValue)));
243         } else {
244             return std::pair(false, value);
245         }
246     }
247     return std::pair(true, value);
248 }
249 
SetPropertyInlinedPropsWithRep(const JSThread * thread,uint32_t index,JSTaggedValue value)250 void JSObject::SetPropertyInlinedPropsWithRep(const JSThread *thread, uint32_t index, JSTaggedValue value)
251 {
252     auto layout = LayoutInfo::Cast(GetJSHClass()->GetLayout().GetTaggedObject());
253     auto attr = layout->GetAttr(index);
254     if (attr.IsTaggedRep()) {
255         SetPropertyInlinedProps<true>(thread, index, value);
256     } else {
257         SetPropertyInlinedProps<false>(thread, index, value);
258     }
259 }
260 
261 template <bool needBarrier>
SetPropertyInlinedProps(const JSThread * thread,uint32_t index,JSTaggedValue value)262 void JSObject::SetPropertyInlinedProps(const JSThread *thread, uint32_t index, JSTaggedValue value)
263 {
264     SetPropertyInlinedProps<needBarrier>(thread, GetJSHClass(), index, value);
265 }
266 
GetPropertyInlinedPropsWithRep(uint32_t index,PropertyAttributes attr)267 JSTaggedValue JSObject::GetPropertyInlinedPropsWithRep(uint32_t index, PropertyAttributes attr) const
268 {
269     return GetPropertyInlinedPropsWithRep(GetJSHClass(), index, attr);
270 }
271 
GetPropertyInlinedPropsWithRep(const JSHClass * hclass,uint32_t index,PropertyAttributes attr)272 JSTaggedValue JSObject::GetPropertyInlinedPropsWithRep(const JSHClass *hclass, uint32_t index,
273                                                        PropertyAttributes attr) const
274 {
275     auto value = GetPropertyInlinedProps(hclass, index);
276     if (attr.IsDoubleRep()) {
277         value = JSTaggedValue(bit_cast<double>(value.GetRawData()));
278     } else if (attr.IsIntRep()) {
279         value = JSTaggedValue(static_cast<int32_t>(value.GetRawData()));
280     }
281     return value;
282 }
283 
GetPropertyInlinedProps(uint32_t index)284 JSTaggedValue JSObject::GetPropertyInlinedProps(uint32_t index) const
285 {
286     return GetPropertyInlinedProps(GetJSHClass(), index);
287 }
288 
289 template <bool needBarrier>
SetPropertyInlinedProps(const JSThread * thread,const JSHClass * hclass,uint32_t index,JSTaggedValue value)290 void JSObject::SetPropertyInlinedProps(const JSThread *thread, const JSHClass *hclass, uint32_t index,
291                                        JSTaggedValue value)
292 {
293     uint32_t offset = hclass->GetInlinedPropertiesOffset(index);
294     if (needBarrier) {
295         SET_VALUE_WITH_BARRIER(thread, this, offset, value);
296     } else {
297         SET_VALUE_PRIMITIVE(this, offset, value);
298     }
299 }
300 
GetPropertyInlinedProps(const JSHClass * hclass,uint32_t index)301 JSTaggedValue JSObject::GetPropertyInlinedProps(const JSHClass *hclass, uint32_t index) const
302 {
303     uint32_t offset = hclass->GetInlinedPropertiesOffset(index);
304     return JSTaggedValue(GET_VALUE(this, offset));
305 }
306 
GetProperty(const JSHClass * hclass,PropertyAttributes attr)307 JSTaggedValue JSObject::GetProperty(const JSHClass *hclass, PropertyAttributes attr) const
308 {
309     if (attr.IsInlinedProps()) {
310         return GetPropertyInlinedPropsWithRep(hclass, attr.GetOffset(), attr);
311     }
312     TaggedArray *array = TaggedArray::Cast(GetProperties().GetTaggedObject());
313     return array->Get(attr.GetOffset() - hclass->GetInlinedProperties());
314 }
315 
316 template <bool needBarrier>
SetProperty(const JSThread * thread,const JSHClass * hclass,PropertyAttributes attr,JSTaggedValue value)317 void JSObject::SetProperty(const JSThread *thread, const JSHClass *hclass, PropertyAttributes attr, JSTaggedValue value)
318 {
319     if (attr.IsInlinedProps()) {
320         SetPropertyInlinedProps<needBarrier>(thread, hclass, attr.GetOffset(), value);
321     } else {
322         TaggedArray *array = TaggedArray::Cast(GetProperties().GetTaggedObject());
323         array->Set<needBarrier>(thread, attr.GetOffset() - hclass->GetInlinedProperties(), value);
324     }
325 }
326 
ShouldTransToDict(uint32_t capacity,uint32_t index)327 inline bool JSObject::ShouldTransToDict(uint32_t capacity, uint32_t index)
328 {
329     if (index < capacity) {
330         return false;
331     }
332 
333     if (index - capacity > MAX_GAP) {
334         return true;
335     }
336 
337     if (index >= static_cast<uint32_t>(INT32_MAX)) {
338         return true;
339     }
340 
341     if (capacity >= MIN_GAP) {
342         return index > capacity * FAST_ELEMENTS_FACTOR;
343     }
344 
345     return false;
346 }
347 
ComputeElementCapacity(uint32_t oldCapacity)348 inline uint32_t JSObject::ComputeElementCapacity(uint32_t oldCapacity)
349 {
350     uint32_t newCapacity = oldCapacity + (oldCapacity >> 1U);
351     return newCapacity > MIN_ELEMENTS_LENGTH ? newCapacity : MIN_ELEMENTS_LENGTH;
352 }
353 
ComputePropertyCapacity(uint32_t oldCapacity)354 inline uint32_t JSObject::ComputePropertyCapacity(uint32_t oldCapacity)
355 {
356     uint32_t newCapacity = static_cast<uint32_t>(oldCapacity + PROPERTIES_GROW_SIZE);
357     return newCapacity > JSHClass::MAX_CAPACITY_OF_OUT_OBJECTS ? JSHClass::MAX_CAPACITY_OF_OUT_OBJECTS
358                                                                : newCapacity;
359 }
360 
361 // static
362 template<ElementTypes types>
CreateListFromArrayLike(JSThread * thread,const JSHandle<JSTaggedValue> & obj)363 JSHandle<JSTaggedValue> JSObject::CreateListFromArrayLike(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
364 {
365     // 3. If Type(obj) is not Object, throw a TypeError exception.
366     if (!obj->IsECMAObject()) {
367         THROW_TYPE_ERROR_AND_RETURN(thread, "CreateListFromArrayLike must accept object",
368                                     JSHandle<JSTaggedValue>(thread, JSTaggedValue::Exception()));
369     }
370     if (obj->IsTypedArray()) {
371         uint32_t len = JSHandle<JSTypedArray>::Cast(obj)->GetArrayLength();
372         JSHandle<TaggedArray> array = thread->GetEcmaVM()->GetFactory()->NewTaggedArray(len);
373         JSTypedArray::FastCopyElementToArray(thread, obj, array);
374         // c. ReturnIfAbrupt(next).
375         RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
376         return JSHandle<JSTaggedValue>(array);
377     }
378     // 4. Let len be ToLength(Get(obj, "length")).
379     JSHandle<JSTaggedValue> lengthKeyHandle = thread->GlobalConstants()->GetHandledLengthString();
380 
381     JSHandle<JSTaggedValue> value = GetProperty(thread, obj, lengthKeyHandle).GetValue();
382     JSTaggedNumber number = JSTaggedValue::ToLength(thread, value);
383     // 5. ReturnIfAbrupt(len).
384     RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
385     if (number.GetNumber() > MAX_ELEMENT_INDEX) {
386         THROW_TYPE_ERROR_AND_RETURN(thread, "len is bigger than 2^32 - 1",
387                                     JSHandle<JSTaggedValue>(thread, JSTaggedValue::Exception()));
388     }
389 
390     uint32_t len = number.ToUint32();
391     // 6. Let list be an empty List.
392     JSHandle<TaggedArray> array = thread->GetEcmaVM()->GetFactory()->NewTaggedArray(len);
393 
394     // 8. Repeat while index < len
395     for (uint32_t i = 0; i < len; i++) {
396         JSTaggedValue next = JSTaggedValue::GetProperty(thread, obj, i).GetValue().GetTaggedValue();
397         // c. ReturnIfAbrupt(next).
398         RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
399 
400         if constexpr (types == ElementTypes::STRING_AND_SYMBOL) {
401             if (!next.IsString() && !next.IsSymbol()) {
402                 THROW_TYPE_ERROR_AND_RETURN(thread, "CreateListFromArrayLike: not an element of elementTypes",
403                                             JSHandle<JSTaggedValue>(thread, JSTaggedValue::Exception()));
404             }
405         }
406 
407         array->Set(thread, i, next);
408     }
409     return JSHandle<JSTaggedValue>(array);
410 }
411 
ShouldGetValueFromBox(ObjectOperator * op)412 inline JSTaggedValue JSObject::ShouldGetValueFromBox(ObjectOperator *op)
413 {
414     JSTaggedValue result = op->GetValue();
415     if (result.IsPropertyBox()) {
416         result = PropertyBox::Cast(result.GetTaggedObject())->GetValue();
417     }
418     return result;
419 }
420 
CheckHClassHit(const JSHandle<JSObject> & obj,const JSHandle<JSHClass> & cls)421 inline bool JSObject::CheckHClassHit(const JSHandle<JSObject> &obj, const JSHandle<JSHClass> &cls)
422 {
423     return obj->GetJSHClass() == *cls;
424 }
425 
SetValuesOrEntries(JSThread * thread,const JSHandle<TaggedArray> & prop,uint32_t index,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value,PropertyKind kind)426 inline uint32_t JSObject::SetValuesOrEntries(JSThread *thread, const JSHandle<TaggedArray> &prop, uint32_t index,
427                                              const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &value,
428                                              PropertyKind kind)
429 {
430     if (kind == PropertyKind::VALUE) {
431         prop->Set(thread, index++, value);
432         return index;
433     }
434     JSHandle<TaggedArray> keyValue = thread->GetEcmaVM()->GetFactory()->NewTaggedArray(2);  // 2: key-value pair
435     keyValue->Set(thread, 0, key);
436     keyValue->Set(thread, 1, value);
437     JSHandle<JSArray> entry = JSArray::CreateArrayFromList(thread, keyValue);
438     prop->Set(thread, index++, entry.GetTaggedValue());
439     return index;
440 }
441 
GetOwnEnumerableNamesInFastMode(JSThread * thread,const JSHandle<JSObject> & obj,uint32_t * copyLengthOfKeys,uint32_t * copyLengthOfElements)442 inline std::pair<JSHandle<TaggedArray>, JSHandle<TaggedArray>> JSObject::GetOwnEnumerableNamesInFastMode(
443     JSThread *thread, const JSHandle<JSObject> &obj, uint32_t *copyLengthOfKeys, uint32_t *copyLengthOfElements)
444 {
445     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
446     uint32_t numOfKeys = obj->GetNumberOfKeys();
447     uint32_t numOfElements = obj->GetNumberOfElements();
448     JSHandle<TaggedArray> elementArray = numOfElements > 0 ? JSObject::GetEnumElementKeys(
449         thread, obj, 0, numOfElements, copyLengthOfElements) : factory->EmptyArray();
450     JSHandle<TaggedArray> keyArray = numOfKeys > 0 ? JSObject::GetAllEnumKeys(
451         thread, obj, 0, numOfKeys, copyLengthOfKeys) : factory->EmptyArray();
452     return std::make_pair(keyArray, elementArray);
453 }
454 
455 }  //  namespace panda::ecmascript
456 #endif  // ECMASCRIPT_JSOBJECT_INL_H
457