• 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/base/number_helper.h"
19 #include "ecmascript/ecma_vm.h"
20 #include "ecmascript/js_array.h"
21 #include "ecmascript/js_hclass.h"
22 #include "ecmascript/js_tagged_number.h"
23 #include "ecmascript/js_tagged_value-inl.h"
24 
25 namespace panda::ecmascript {
Get(JSHandle<JSObject> receiver,uint32_t idx)26 JSTaggedValue ElementAccessor::Get(JSHandle<JSObject> receiver, uint32_t idx)
27 {
28     TaggedArray *elements = TaggedArray::Cast(receiver->GetElements());
29     ASSERT(idx < elements->GetLength());
30     ElementsKind kind = receiver->GetClass()->GetElementsKind();
31     if (!elements->GetClass()->IsMutantTaggedArray()) {
32         kind = ElementsKind::GENERIC;
33     }
34     // Note: Here we can't statically decide the element type is a primitive or heap object, especially for
35     //       dynamically-typed languages like JavaScript. So we simply skip the read-barrier.
36     size_t offset = JSTaggedValue::TaggedTypeSize() * idx;
37     // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon)
38     JSTaggedType rawValue = Barriers::GetValue<JSTaggedType>(elements->GetData(), offset);
39     return GetTaggedValueWithElementsKind(rawValue, kind);
40 }
41 
Get(JSObject * receiver,uint32_t idx)42 JSTaggedValue ElementAccessor::Get(JSObject *receiver, uint32_t idx)
43 {
44     TaggedArray *elements = TaggedArray::Cast(receiver->GetElements());
45     ASSERT(idx < elements->GetLength());
46     ElementsKind kind = receiver->GetClass()->GetElementsKind();
47     if (!elements->GetClass()->IsMutantTaggedArray()) {
48         kind = ElementsKind::GENERIC;
49     }
50     // Note: Here we can't statically decide the element type is a primitive or heap object, especially for
51     //       dynamically-typed languages like JavaScript. So we simply skip the read-barrier.
52     size_t offset = JSTaggedValue::TaggedTypeSize() * idx;
53     // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon)
54     JSTaggedType rawValue = Barriers::GetValue<JSTaggedType>(elements->GetData(), offset);
55     return GetTaggedValueWithElementsKind(rawValue, kind);
56 }
57 
IsDictionaryMode(JSHandle<JSObject> receiver)58 bool ElementAccessor::IsDictionaryMode(JSHandle<JSObject> receiver)
59 {
60     TaggedArray *elements = TaggedArray::Cast(receiver->GetElements());
61     return elements->GetClass()->IsDictionary();
62 }
63 
IsDictionaryMode(JSObject * receiver)64 bool ElementAccessor::IsDictionaryMode(JSObject *receiver)
65 {
66     TaggedArray *elements = TaggedArray::Cast(receiver->GetElements());
67     return elements->GetClass()->IsDictionary();
68 }
69 
GetElementsLength(JSHandle<JSObject> receiver)70 uint32_t ElementAccessor::GetElementsLength(JSHandle<JSObject> receiver)
71 {
72     TaggedArray *elements = TaggedArray::Cast(receiver->GetElements());
73     return elements->GetLength();
74 }
75 
GetElementsLength(JSObject * receiver)76 uint32_t ElementAccessor::GetElementsLength(JSObject *receiver)
77 {
78     TaggedArray *elements = TaggedArray::Cast(receiver->GetElements());
79     return elements->GetLength();
80 }
81 
GetTaggedValueWithElementsKind(JSTaggedType rawValue,ElementsKind kind)82 JSTaggedValue ElementAccessor::GetTaggedValueWithElementsKind(JSTaggedType rawValue, ElementsKind kind)
83 {
84     JSTaggedValue convertedValue = JSTaggedValue::Hole();
85     if (rawValue == base::SPECIAL_HOLE) {
86         return convertedValue;
87     }
88     switch (kind) {
89         case ElementsKind::INT:
90         case ElementsKind::HOLE_INT:
91             convertedValue = JSTaggedValue(static_cast<int>(rawValue));
92             break;
93         case ElementsKind::NUMBER:
94         case ElementsKind::HOLE_NUMBER:
95             convertedValue = JSTaggedValue(base::bit_cast<double>(rawValue));
96             break;
97         case ElementsKind::TAGGED:
98         case ElementsKind::STRING:
99         case ElementsKind::HOLE_TAGGED:
100         case ElementsKind::HOLE_STRING:
101             convertedValue = JSTaggedValue(rawValue);
102             break;
103         default:
104             LOG_ECMA(FATAL) << "Trying to Get TaggedValue With Unknown ElementsKind";
105             UNREACHABLE();
106             break;
107     }
108     return convertedValue;
109 }
110 
ConvertTaggedValueWithElementsKind(JSTaggedValue rawValue,ElementsKind kind)111 JSTaggedType ElementAccessor::ConvertTaggedValueWithElementsKind(JSTaggedValue rawValue, ElementsKind kind)
112 {
113     JSTaggedType convertedValue = base::SPECIAL_HOLE;
114     if (rawValue.IsHole() && Elements::IsInNumbers(kind)) {
115         return convertedValue;
116     }
117     switch (kind) {
118         case ElementsKind::INT:
119         case ElementsKind::HOLE_INT:
120             convertedValue = static_cast<JSTaggedType>(rawValue.GetInt());
121             break;
122         case ElementsKind::NUMBER:
123         case ElementsKind::HOLE_NUMBER:
124             if (rawValue.IsInt()) {
125                 int intValue = rawValue.GetInt();
126                 convertedValue = base::bit_cast<JSTaggedType>(static_cast<double>(intValue));
127             } else {
128                 convertedValue = base::bit_cast<JSTaggedType>(rawValue.GetDouble());
129             }
130             break;
131         case ElementsKind::TAGGED:
132         case ElementsKind::STRING:
133         case ElementsKind::HOLE_TAGGED:
134         case ElementsKind::HOLE_STRING:
135             convertedValue = rawValue.GetRawData();
136             break;
137         default:
138             LOG_ECMA(FATAL) << "Trying to Convert TaggedValue With Unknown ElementsKind";
139             UNREACHABLE();
140             break;
141     }
142     return convertedValue;
143 }
144 }  // namespace panda::ecmascript
145