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 #include "ecmascript/layout_info-inl.h"
17
18 #include "ecmascript/ecma_string.h"
19 #include "ecmascript/filter_helper.h"
20 #include "ecmascript/js_object-inl.h"
21 #include "ecmascript/js_symbol.h"
22 #include "ecmascript/mem/assert_scope.h"
23
24 namespace panda::ecmascript {
Initialize(const JSThread * thread,int num)25 void LayoutInfo::Initialize(const JSThread *thread, int num)
26 {
27 SetExtraLength(num);
28 int propNum = GetPropertiesCapacity();
29 auto attr = PropertyAttributes();
30 for (int i = 0; i < propNum; i++) {
31 SetPropertyInit(thread, i, JSTaggedValue::Hole(), attr);
32 }
33 }
34
AddKey(const JSThread * thread,int index,const JSTaggedValue & key,const PropertyAttributes & attr)35 void LayoutInfo::AddKey(const JSThread *thread, [[maybe_unused]] int index, const JSTaggedValue &key,
36 const PropertyAttributes &attr)
37 {
38 DISALLOW_GARBAGE_COLLECTION;
39 int number = NumberOfElements();
40 ASSERT(attr.GetOffset() == static_cast<uint32_t>(number));
41 ASSERT(number + 1 <= GetPropertiesCapacity());
42 ASSERT(number == index);
43 SetNumberOfElements(thread, number + 1);
44 SetPropertyInit(thread, number, key, attr);
45
46 uint32_t keyHash = key.GetKeyHashCode();
47 int insertIndex = number;
48 for (; insertIndex > 0; --insertIndex) {
49 JSTaggedValue prevKey = GetSortedKey(insertIndex - 1);
50 if (prevKey.GetKeyHashCode() <= keyHash) {
51 break;
52 }
53 SetSortedIndex(thread, insertIndex, GetSortedIndex(insertIndex - 1));
54 }
55 SetSortedIndex(thread, insertIndex, number);
56 }
57
GetAllKeys(const JSThread * thread,int end,int offset,TaggedArray * keyArray,const JSHandle<JSObject> object)58 void LayoutInfo::GetAllKeys(const JSThread *thread, int end, int offset, TaggedArray *keyArray,
59 const JSHandle<JSObject> object)
60 {
61 ASSERT(end <= NumberOfElements());
62 ASSERT_PRINT(offset + end <= static_cast<int>(keyArray->GetLength()),
63 "keyArray capacity is not enough for dictionary");
64
65 DISALLOW_GARBAGE_COLLECTION;
66 int enumKeys = 0;
67 for (int i = 0; i < end; i++) {
68 JSTaggedValue key = GetKey(i);
69 if (key.IsString()) {
70 if (IsUninitializedProperty(object, i)) {
71 continue;
72 }
73 keyArray->Set(thread, enumKeys + offset, key);
74 enumKeys++;
75 }
76 }
77
78 if (enumKeys < end) {
79 for (int i = 0; i < end; i++) {
80 JSTaggedValue key = GetKey(i);
81 if (key.IsSymbol()) {
82 keyArray->Set(thread, enumKeys + offset, key);
83 enumKeys++;
84 }
85 }
86 }
87 }
GetAllKeysByFilter(const JSThread * thread,uint32_t numberOfProps,uint32_t & keyArrayEffectivelength,TaggedArray * keyArray,const JSHandle<JSObject> object,uint32_t filter)88 void LayoutInfo::GetAllKeysByFilter(const JSThread *thread, uint32_t numberOfProps, uint32_t &keyArrayEffectivelength,
89 TaggedArray *keyArray, const JSHandle<JSObject> object, uint32_t filter)
90 {
91 ASSERT(numberOfProps <= static_cast<uint32_t>(NumberOfElements()));
92 ASSERT_PRINT(keyArrayEffectivelength + numberOfProps <= keyArray->GetLength(),
93 "keyArray capacity is not enough for dictionary");
94
95 DISALLOW_GARBAGE_COLLECTION;
96 uint32_t enumKeys = 0;
97 for (uint32_t i = 0; i < numberOfProps; i++) {
98 JSTaggedValue key = GetKey(static_cast<int>(i));
99 if (key.IsString() && !(filter & NATIVE_KEY_SKIP_STRINGS)) {
100 if (IsUninitializedProperty(object, i)) {
101 continue;
102 }
103 PropertyAttributes attr = GetAttr(static_cast<int>(i));
104 bool bIgnore = FilterHelper::IgnoreKeyByFilter<PropertyAttributes>(attr, filter);
105 if (bIgnore) {
106 continue;
107 }
108 keyArray->Set(thread, keyArrayEffectivelength, key);
109 keyArrayEffectivelength++;
110 enumKeys++;
111 }
112 }
113
114 if (enumKeys < numberOfProps) {
115 for (uint32_t i = 0; i < numberOfProps; i++) {
116 JSTaggedValue key = GetKey(static_cast<int>(i));
117 if (key.IsSymbol() && !(filter & NATIVE_KEY_SKIP_SYMBOLS)) {
118 PropertyAttributes attr = GetAttr(static_cast<int>(i));
119 bool bIgnore = FilterHelper::IgnoreKeyByFilter<PropertyAttributes>(attr, filter);
120 if (bIgnore) {
121 continue;
122 }
123 keyArray->Set(thread, keyArrayEffectivelength, key);
124 keyArrayEffectivelength++;
125 }
126 }
127 }
128 }
129
GetAllKeys(int end,std::vector<JSTaggedValue> & keyVector,const JSHandle<JSObject> object)130 void LayoutInfo::GetAllKeys(int end, std::vector<JSTaggedValue> &keyVector, const JSHandle<JSObject> object)
131 {
132 ASSERT(end <= NumberOfElements());
133 for (int i = 0; i < end; i++) {
134 JSTaggedValue key = GetKey(i);
135 if (key.IsString() || key.IsSymbol()) {
136 if (IsUninitializedProperty(object, i)) {
137 continue;
138 }
139 keyVector.emplace_back(key);
140 }
141 }
142 }
143
GetAllEnumKeys(const JSThread * thread,int end,int offset,TaggedArray * keyArray,uint32_t * keys,const JSHandle<JSObject> object)144 void LayoutInfo::GetAllEnumKeys(const JSThread *thread, int end, int offset, TaggedArray *keyArray,
145 uint32_t *keys, const JSHandle<JSObject> object)
146 {
147 ASSERT(end <= NumberOfElements());
148 ASSERT_PRINT(offset + end <= static_cast<int>(keyArray->GetLength()),
149 "keyArray capacity is not enough for dictionary");
150
151 DISALLOW_GARBAGE_COLLECTION;
152 int enumKeys = 0;
153 for (int i = 0; i < end; i++) {
154 JSTaggedValue key = GetKey(i);
155 if (key.IsString() && GetAttr(i).IsEnumerable()) {
156 if (IsUninitializedProperty(object, i)) {
157 continue;
158 }
159 keyArray->Set(thread, enumKeys + offset, key);
160 enumKeys++;
161 }
162 }
163 *keys += enumKeys;
164 }
165
IsUninitializedProperty(const JSHandle<JSObject> object,uint32_t index)166 bool LayoutInfo::IsUninitializedProperty(const JSHandle<JSObject> object, uint32_t index)
167 {
168 PropertyAttributes attr = GetAttr(index);
169 if (!attr.IsInlinedProps()) {
170 return false;
171 }
172
173 JSTaggedValue val = object->GetPropertyInlinedProps(attr.GetOffset());
174 return val.IsHole();
175 }
176
DumpFieldIndexForProfile(int index,PGOHClassLayoutDesc & desc,PGOObjKind kind)177 void LayoutInfo::DumpFieldIndexForProfile(int index, PGOHClassLayoutDesc &desc, PGOObjKind kind)
178 {
179 auto key = GetKey(index);
180 if (key.IsString()) {
181 auto attr = GetAttr(index);
182 TrackType type = attr.GetTrackType();
183 bool isAccessor = attr.IsAccessor();
184 auto keyString = EcmaStringAccessor(key).ToCString();
185 desc.UpdateKeyAndDesc(keyString.c_str(), PGOHandler(type, isAccessor), kind);
186 }
187 }
188 } // namespace panda::ecmascript
189