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