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());
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::GetValue<JSTaggedType>(elements->GetData(), 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());
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::GetValue<JSTaggedType>(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(JSHandle<TaggedArray> elements,uint32_t idx,ElementsKind kind)62 JSTaggedValue ElementAccessor::FastGet(JSHandle<TaggedArray> elements, uint32_t idx, ElementsKind kind)
63 {
64 ASSERT(idx < elements->GetLength());
65 size_t offset = JSTaggedValue::TaggedTypeSize() * idx;
66 // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon)
67 JSTaggedType rawValue = Barriers::GetValue<JSTaggedType>(elements->GetData(), offset);
68 return GetTaggedValueWithElementsKind(rawValue, kind);
69 }
70
IsDictionaryMode(JSHandle<JSObject> receiver)71 bool ElementAccessor::IsDictionaryMode(JSHandle<JSObject> receiver)
72 {
73 TaggedArray *elements = TaggedArray::Cast(receiver->GetElements());
74 return elements->GetClass()->IsDictionary();
75 }
76
IsDictionaryMode(JSObject * receiver)77 bool ElementAccessor::IsDictionaryMode(JSObject *receiver)
78 {
79 TaggedArray *elements = TaggedArray::Cast(receiver->GetElements());
80 return elements->GetClass()->IsDictionary();
81 }
82
GetElementsLength(JSHandle<JSObject> receiver)83 uint32_t ElementAccessor::GetElementsLength(JSHandle<JSObject> receiver)
84 {
85 TaggedArray *elements = TaggedArray::Cast(receiver->GetElements());
86 return elements->GetLength();
87 }
88
GetElementsLength(JSObject * receiver)89 uint32_t ElementAccessor::GetElementsLength(JSObject *receiver)
90 {
91 TaggedArray *elements = TaggedArray::Cast(receiver->GetElements());
92 return elements->GetLength();
93 }
94
GetTaggedValueWithElementsKind(JSTaggedType rawValue,ElementsKind kind)95 JSTaggedValue ElementAccessor::GetTaggedValueWithElementsKind(JSTaggedType rawValue, ElementsKind kind)
96 {
97 JSTaggedValue convertedValue = JSTaggedValue::Hole();
98 if (rawValue == base::SPECIAL_HOLE) {
99 return convertedValue;
100 }
101 switch (kind) {
102 case ElementsKind::INT:
103 case ElementsKind::HOLE_INT:
104 convertedValue = JSTaggedValue(static_cast<int>(rawValue));
105 break;
106 case ElementsKind::NUMBER:
107 case ElementsKind::HOLE_NUMBER:
108 convertedValue = JSTaggedValue(base::bit_cast<double>(rawValue));
109 break;
110 case ElementsKind::HOLE:
111 case ElementsKind::NONE:
112 case ElementsKind::TAGGED:
113 case ElementsKind::STRING:
114 case ElementsKind::HOLE_TAGGED:
115 case ElementsKind::HOLE_STRING:
116 convertedValue = JSTaggedValue(rawValue);
117 break;
118 default:
119 LOG_ECMA(FATAL) << "Trying to Get TaggedValue With Unknown ElementsKind";
120 UNREACHABLE();
121 break;
122 }
123 return convertedValue;
124 }
125
ConvertTaggedValueWithElementsKind(JSTaggedValue rawValue,ElementsKind kind)126 JSTaggedType ElementAccessor::ConvertTaggedValueWithElementsKind(JSTaggedValue rawValue, ElementsKind kind)
127 {
128 JSTaggedType convertedValue = base::SPECIAL_HOLE;
129 if (rawValue.IsHole() && Elements::IsInNumbers(kind)) {
130 return convertedValue;
131 }
132 switch (kind) {
133 case ElementsKind::INT:
134 case ElementsKind::HOLE_INT:
135 convertedValue = static_cast<JSTaggedType>(rawValue.GetInt());
136 break;
137 case ElementsKind::NUMBER:
138 case ElementsKind::HOLE_NUMBER:
139 if (rawValue.IsInt()) {
140 int intValue = rawValue.GetInt();
141 convertedValue = base::bit_cast<JSTaggedType>(static_cast<double>(intValue));
142 } else {
143 convertedValue = base::bit_cast<JSTaggedType>(rawValue.GetDouble());
144 }
145 break;
146 case ElementsKind::HOLE:
147 case ElementsKind::NONE:
148 case ElementsKind::TAGGED:
149 case ElementsKind::STRING:
150 case ElementsKind::HOLE_TAGGED:
151 case ElementsKind::HOLE_STRING:
152 convertedValue = rawValue.GetRawData();
153 break;
154 default:
155 LOG_ECMA(FATAL) << "Trying to Convert TaggedValue With Unknown ElementsKind";
156 UNREACHABLE();
157 break;
158 }
159 return convertedValue;
160 }
161
CopyJSArrayObject(const JSThread * thread,JSHandle<JSObject> srcObj,JSHandle<JSObject> dstObj,uint32_t effectiveLength)162 void ElementAccessor::CopyJSArrayObject(const JSThread *thread, JSHandle<JSObject>srcObj, JSHandle<JSObject>dstObj,
163 uint32_t effectiveLength)
164 {
165 ASSERT(effectiveLength <= GetElementsLength(srcObj));
166 ASSERT(effectiveLength <= GetElementsLength(dstObj));
167 for (uint32_t i = 0; i < effectiveLength; i++) {
168 JSHandle<JSTaggedValue> value(thread, Get(thread, srcObj, i));
169 Set(thread, dstObj, i, value, true);
170 }
171 }
172
CopyJSArrayToTaggedArray(const JSThread * thread,JSHandle<JSObject> srcObj,JSHandle<TaggedArray> dstElements,uint32_t effectiveLength)173 void ElementAccessor::CopyJSArrayToTaggedArray(const JSThread *thread, JSHandle<JSObject>srcObj,
174 JSHandle<TaggedArray>dstElements, uint32_t effectiveLength)
175 {
176 ASSERT(effectiveLength <= GetElementsLength(srcObj));
177 ASSERT(effectiveLength <= dstElements->GetLength());
178 for (uint32_t i = 0; i < effectiveLength; i++) {
179 JSHandle<JSTaggedValue> value(thread, Get(thread, srcObj, i));
180 dstElements->Set(thread, i, value);
181 }
182 }
183 } // namespace panda::ecmascript
184