• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 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/element_accessor.h"
17 
18 #include "ecmascript/js_tagged_value-inl.h"
19 #include "ecmascript/tagged_array-inl.h"
20 
21 namespace panda::ecmascript {
Get(const JSThread * thread,JSHandle<JSObject> receiver,uint32_t idx)22 JSTaggedValue ElementAccessor::Get(const JSThread *thread, JSHandle<JSObject> receiver, uint32_t idx)
23 {
24     TaggedArray *elements = TaggedArray::Cast(receiver->GetElements(thread));
25     ASSERT(idx < elements->GetLength());
26     // Note: Here we can't statically decide the element type is a primitive or heap object, especially for
27     //       dynamically-typed languages like JavaScript. So we simply skip the read-barrier.
28     size_t offset = JSTaggedValue::TaggedTypeSize() * idx;
29     // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon)
30     JSTaggedType rawValue = Barriers::GetTaggedValue(thread, elements, TaggedArray::DATA_OFFSET + offset);
31     if (UNLIKELY(thread->IsEnableMutantArray())) {
32         ElementsKind kind = receiver->GetClass()->GetElementsKind();
33         if (!elements->GetClass()->IsMutantTaggedArray()) {
34             kind = ElementsKind::GENERIC;
35         }
36         return GetTaggedValueWithElementsKind(rawValue, kind);
37     } else {
38         return JSTaggedValue(rawValue);
39     }
40 }
41 
Get(const JSThread * thread,JSObject * receiver,uint32_t idx)42 JSTaggedValue ElementAccessor::Get(const JSThread *thread, JSObject *receiver, uint32_t idx)
43 {
44     TaggedArray *elements = TaggedArray::Cast(receiver->GetElements(thread));
45     ASSERT(idx < elements->GetLength());
46     // Note: Here we can't statically decide the element type is a primitive or heap object, especially for
47     //       dynamically-typed languages like JavaScript. So we simply skip the read-barrier.
48     size_t offset = JSTaggedValue::TaggedTypeSize() * idx;
49     // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon)
50     JSTaggedType rawValue = Barriers::GetTaggedValue(thread, elements->GetData(), offset);
51     if (UNLIKELY(thread->IsEnableMutantArray())) {
52         ElementsKind kind = receiver->GetClass()->GetElementsKind();
53         if (!elements->GetClass()->IsMutantTaggedArray()) {
54             kind = ElementsKind::GENERIC;
55         }
56         return GetTaggedValueWithElementsKind(rawValue, kind);
57     } else {
58         return JSTaggedValue(rawValue);
59     }
60 }
61 
FastGet(const JSThread * thread,JSHandle<TaggedArray> elements,uint32_t idx,ElementsKind kind)62 JSTaggedValue ElementAccessor::FastGet(const JSThread *thread, JSHandle<TaggedArray> elements, uint32_t idx,
63                                        ElementsKind kind)
64 {
65     ASSERT(idx < elements->GetLength());
66     size_t offset = JSTaggedValue::TaggedTypeSize() * idx;
67     // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon)
68     JSTaggedType rawValue = Barriers::GetTaggedValue(thread, elements->GetData(), offset);
69     return GetTaggedValueWithElementsKind(rawValue, kind);
70 }
71 
IsDictionaryMode(const JSThread * thread,JSHandle<JSObject> receiver)72 bool ElementAccessor::IsDictionaryMode(const JSThread *thread, JSHandle<JSObject> receiver)
73 {
74     TaggedArray *elements = TaggedArray::Cast(receiver->GetElements(thread));
75     return elements->GetClass()->IsDictionary();
76 }
77 
IsDictionaryMode(const JSThread * thread,JSObject * receiver)78 bool ElementAccessor::IsDictionaryMode(const JSThread *thread, JSObject *receiver)
79 {
80     TaggedArray *elements = TaggedArray::Cast(receiver->GetElements(thread));
81     return elements->GetClass()->IsDictionary();
82 }
83 
GetElementsLength(const JSThread * thread,JSHandle<JSObject> receiver)84 uint32_t ElementAccessor::GetElementsLength(const JSThread *thread, JSHandle<JSObject> receiver)
85 {
86     TaggedArray *elements = TaggedArray::Cast(receiver->GetElements(thread));
87     return elements->GetLength();
88 }
89 
GetElementsLength(const JSThread * thread,JSObject * receiver)90 uint32_t ElementAccessor::GetElementsLength(const JSThread *thread, JSObject *receiver)
91 {
92     TaggedArray *elements = TaggedArray::Cast(receiver->GetElements(thread));
93     return elements->GetLength();
94 }
95 
GetTaggedValueWithElementsKind(JSTaggedType rawValue,ElementsKind kind)96 JSTaggedValue ElementAccessor::GetTaggedValueWithElementsKind(JSTaggedType rawValue, ElementsKind kind)
97 {
98     JSTaggedValue convertedValue = JSTaggedValue::Hole();
99     if (rawValue == base::SPECIAL_HOLE) {
100         return convertedValue;
101     }
102     switch (kind) {
103         case ElementsKind::INT:
104         case ElementsKind::HOLE_INT:
105             convertedValue = JSTaggedValue(static_cast<int>(rawValue));
106             break;
107         case ElementsKind::NUMBER:
108         case ElementsKind::HOLE_NUMBER:
109             convertedValue = JSTaggedValue(base::bit_cast<double>(rawValue));
110             break;
111         case ElementsKind::HOLE:
112         case ElementsKind::NONE:
113         case ElementsKind::TAGGED:
114         case ElementsKind::STRING:
115         case ElementsKind::HOLE_TAGGED:
116         case ElementsKind::HOLE_STRING:
117             convertedValue = JSTaggedValue(rawValue);
118             break;
119         default:
120             LOG_ECMA(FATAL) << "Trying to Get TaggedValue With Unknown ElementsKind";
121             UNREACHABLE();
122             break;
123     }
124     return convertedValue;
125 }
126 
ConvertTaggedValueWithElementsKind(JSTaggedValue rawValue,ElementsKind kind)127 JSTaggedType ElementAccessor::ConvertTaggedValueWithElementsKind(JSTaggedValue rawValue, ElementsKind kind)
128 {
129     JSTaggedType convertedValue = base::SPECIAL_HOLE;
130     if (rawValue.IsHole() && Elements::IsInNumbers(kind)) {
131         return convertedValue;
132     }
133     switch (kind) {
134         case ElementsKind::INT:
135         case ElementsKind::HOLE_INT:
136             convertedValue = static_cast<JSTaggedType>(rawValue.GetInt());
137             break;
138         case ElementsKind::NUMBER:
139         case ElementsKind::HOLE_NUMBER:
140             if (rawValue.IsInt()) {
141                 int intValue = rawValue.GetInt();
142                 convertedValue = base::bit_cast<JSTaggedType>(static_cast<double>(intValue));
143             } else {
144                 convertedValue = base::bit_cast<JSTaggedType>(rawValue.GetDouble());
145             }
146             break;
147         case ElementsKind::HOLE:
148         case ElementsKind::NONE:
149         case ElementsKind::TAGGED:
150         case ElementsKind::STRING:
151         case ElementsKind::HOLE_TAGGED:
152         case ElementsKind::HOLE_STRING:
153             convertedValue = rawValue.GetRawData();
154             break;
155         default:
156             LOG_ECMA(FATAL) << "Trying to Convert TaggedValue With Unknown ElementsKind";
157             UNREACHABLE();
158             break;
159     }
160     return convertedValue;
161 }
162 
CopyJSArrayObject(const JSThread * thread,JSHandle<JSObject> srcObj,JSHandle<JSObject> dstObj,uint32_t effectiveLength)163 void ElementAccessor::CopyJSArrayObject(const JSThread *thread, JSHandle<JSObject>srcObj, JSHandle<JSObject>dstObj,
164                                         uint32_t effectiveLength)
165 {
166     ASSERT(effectiveLength <= GetElementsLength(thread, srcObj));
167     ASSERT(effectiveLength <= GetElementsLength(thread, dstObj));
168     for (uint32_t i = 0; i < effectiveLength; i++) {
169         JSHandle<JSTaggedValue> value(thread, Get(thread, srcObj, i));
170         Set(thread, dstObj, i, value, true);
171     }
172 }
173 
CopyJSArrayToTaggedArray(const JSThread * thread,JSHandle<JSObject> srcObj,JSHandle<TaggedArray> dstElements,uint32_t effectiveLength)174 void ElementAccessor::CopyJSArrayToTaggedArray(const JSThread *thread, JSHandle<JSObject>srcObj,
175                                                JSHandle<TaggedArray>dstElements, uint32_t effectiveLength)
176 {
177     ASSERT(effectiveLength <= GetElementsLength(thread, srcObj));
178     ASSERT(effectiveLength <= dstElements->GetLength());
179     for (uint32_t i = 0; i < effectiveLength; i++) {
180         JSHandle<JSTaggedValue> value(thread, Get(thread, srcObj, i));
181         dstElements->Set(thread, i, value);
182     }
183 }
184 }  // namespace panda::ecmascript
185