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/js_object-inl.h"
17 #include "pgo_profiler/pgo_profiler_layout.h"
18
19 namespace panda::ecmascript {
20 using PGOHandler = pgo::PGOHandler;
Initialize(const JSThread *thread, int num)21 void LayoutInfo::Initialize(const JSThread *thread, int num)
22 {
23 SetExtraLength(num);
24 int propNum = GetPropertiesCapacity();
25 auto attr = PropertyAttributes();
26 for (int i = 0; i < propNum; i++) {
27 SetPropertyInit(thread, i, JSTaggedValue::Hole(), attr);
28 }
29 }
30
GetAllKeys(const JSThread *thread, int end, int offset, TaggedArray *keyArray, const JSHandle<JSObject> object)31 void LayoutInfo::GetAllKeys(const JSThread *thread, int end, int offset, TaggedArray *keyArray,
32 const JSHandle<JSObject> object)
33 {
34 ASSERT(end <= NumberOfElements());
35 ASSERT_PRINT(offset + end <= static_cast<int>(keyArray->GetLength()),
36 "keyArray capacity is not enough for dictionary");
37
38 DISALLOW_GARBAGE_COLLECTION;
39 int enumKeys = 0;
40 for (int i = 0; i < end; i++) {
41 JSTaggedValue key = GetKey(i);
42 if (key.IsString()) {
43 if (IsUninitializedProperty(*object, i)) {
44 continue;
45 }
46 keyArray->Set(thread, enumKeys + offset, key);
47 enumKeys++;
48 }
49 }
50
51 if (enumKeys < end) {
52 for (int i = 0; i < end; i++) {
53 JSTaggedValue key = GetKey(i);
54 if (key.IsSymbol()) {
55 keyArray->Set(thread, enumKeys + offset, key);
56 enumKeys++;
57 }
58 }
59 }
60 }
GetAllKeysByFilter(const JSThread *thread, uint32_t numberOfProps, uint32_t &keyArrayEffectivelength, TaggedArray *keyArray, const JSHandle<JSObject> object, uint32_t filter)61 void LayoutInfo::GetAllKeysByFilter(const JSThread *thread, uint32_t numberOfProps, uint32_t &keyArrayEffectivelength,
62 TaggedArray *keyArray, const JSHandle<JSObject> object, uint32_t filter)
63 {
64 ASSERT(numberOfProps <= static_cast<uint32_t>(NumberOfElements()));
65 ASSERT_PRINT(keyArrayEffectivelength + numberOfProps <= keyArray->GetLength(),
66 "keyArray capacity is not enough for dictionary");
67
68 DISALLOW_GARBAGE_COLLECTION;
69 uint32_t enumKeys = 0;
70 for (uint32_t i = 0; i < numberOfProps; i++) {
71 JSTaggedValue key = GetKey(static_cast<int>(i));
72 if (key.IsString() && !(filter & NATIVE_KEY_SKIP_STRINGS)) {
73 if (IsUninitializedProperty(*object, i)) {
74 continue;
75 }
76 PropertyAttributes attr = GetAttr(static_cast<int>(i));
77 bool bIgnore = FilterHelper::IgnoreKeyByFilter<PropertyAttributes>(attr, filter);
78 if (bIgnore) {
79 continue;
80 }
81 keyArray->Set(thread, keyArrayEffectivelength, key);
82 keyArrayEffectivelength++;
83 enumKeys++;
84 }
85 }
86
87 if (enumKeys < numberOfProps) {
88 for (uint32_t i = 0; i < numberOfProps; i++) {
89 JSTaggedValue key = GetKey(static_cast<int>(i));
90 if (key.IsSymbol() && !(filter & NATIVE_KEY_SKIP_SYMBOLS)) {
91 PropertyAttributes attr = GetAttr(static_cast<int>(i));
92 bool bIgnore = FilterHelper::IgnoreKeyByFilter<PropertyAttributes>(attr, filter);
93 if (bIgnore) {
94 continue;
95 }
96 keyArray->Set(thread, keyArrayEffectivelength, key);
97 keyArrayEffectivelength++;
98 }
99 }
100 }
101 }
102
GetAllKeysForSerialization(int end, std::vector<JSTaggedValue> &keyVector)103 void LayoutInfo::GetAllKeysForSerialization(int end, std::vector<JSTaggedValue> &keyVector)
104 {
105 ASSERT(end <= NumberOfElements());
106 for (int i = 0; i < end; i++) {
107 JSTaggedValue key = GetKey(i);
108 if (key.IsString() || key.IsSymbol()) {
109 keyVector.emplace_back(key);
110 }
111 }
112 }
113
GetNumOfEnumKeys(int end, const JSObject *object) const114 std::pair<uint32_t, uint32_t> LayoutInfo::GetNumOfEnumKeys(int end, const JSObject *object) const
115 {
116 ASSERT(end <= NumberOfElements());
117 uint32_t enumKeys = 0;
118 uint32_t shadowKeys = 0;
119 for (int i = 0; i < end; i++) {
120 JSTaggedValue key = GetKey(i);
121 if (!key.IsString()) {
122 continue;
123 }
124 if (IsUninitializedProperty(object, i)) {
125 continue;
126 }
127 if (GetAttr(i).IsEnumerable()) {
128 enumKeys++;
129 } else {
130 shadowKeys++;
131 }
132 }
133 return std::make_pair(enumKeys, shadowKeys);
134 }
135
GetAllEnumKeys(JSThread *thread, int end, int offset, JSHandle<TaggedArray> keyArray, uint32_t *keys, JSHandle<TaggedQueue> shadowQueue, const JSHandle<JSObject> object, int32_t lastLength)136 void LayoutInfo::GetAllEnumKeys(JSThread *thread, int end, int offset, JSHandle<TaggedArray> keyArray,
137 uint32_t *keys, JSHandle<TaggedQueue> shadowQueue, const JSHandle<JSObject> object,
138 int32_t lastLength)
139 {
140 ASSERT(end <= NumberOfElements());
141 ASSERT_PRINT(offset <= static_cast<int>(keyArray->GetLength()),
142 "keyArray capacity is not enough for dictionary");
143 JSMutableHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue::Undefined());
144 int enumKeys = 0;
145 for (int i = 0; i < end; i++) {
146 keyHandle.Update(GetKey(i));
147 if (!keyHandle->IsString()) {
148 continue;
149 }
150 if (IsUninitializedProperty(*object, i)) {
151 continue;
152 }
153 if (GetAttr(i).IsEnumerable()) {
154 bool isDuplicated = JSObject::IsDepulicateKeys(thread, keyArray, lastLength, shadowQueue, keyHandle);
155 if (isDuplicated) {
156 continue;
157 }
158 keyArray->Set(thread, enumKeys + offset, keyHandle);
159 enumKeys++;
160 } else {
161 TaggedQueue::PushFixedQueue(thread, shadowQueue, keyHandle);
162 }
163 }
164 *keys += enumKeys;
165 }
166
GetAllEnumKeys(JSThread *thread, int end, int offset, JSHandle<TaggedArray> keyArray, uint32_t *keys, const JSHandle<JSObject> object)167 void LayoutInfo::GetAllEnumKeys(JSThread *thread, int end, int offset, JSHandle<TaggedArray> keyArray,
168 uint32_t *keys, const JSHandle<JSObject> object)
169 {
170 ASSERT(end <= NumberOfElements());
171 ASSERT_PRINT(offset <= static_cast<int>(keyArray->GetLength()),
172 "keyArray capacity is not enough for dictionary");
173 JSMutableHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue::Undefined());
174 int enumKeys = 0;
175 for (int i = 0; i < end; i++) {
176 keyHandle.Update(GetKey(i));
177 if (keyHandle->IsString() && GetAttr(i).IsEnumerable()) {
178 if (IsUninitializedProperty(*object, i)) {
179 continue;
180 }
181 keyArray->Set(thread, enumKeys + offset, keyHandle);
182 enumKeys++;
183 }
184 }
185 *keys += enumKeys;
186 }
187
IsUninitializedProperty(const JSObject *object, uint32_t index) const188 bool LayoutInfo::IsUninitializedProperty(const JSObject *object, uint32_t index) const
189 {
190 PropertyAttributes attr = GetAttr(index);
191 if (!attr.IsInlinedProps()) {
192 return false;
193 }
194
195 JSTaggedValue val = object->GetPropertyInlinedPropsWithRep(attr.GetOffset(), attr);
196 return val.IsHole();
197 }
198
GetSymbolKeyString(JSTaggedValue key)199 CString LayoutInfo::GetSymbolKeyString(JSTaggedValue key)
200 {
201 auto symbol = JSSymbol::Cast(key);
202 if (!symbol->HasId()) {
203 return "";
204 }
205 auto id = symbol->GetPrivateId();
206 auto symbolDesc = symbol->GetDescription();
207 if (symbolDesc.IsUndefined()) {
208 return ToCString(id);
209 }
210 if (!symbolDesc.IsString()) {
211 return "";
212 }
213 CString str = EcmaStringAccessor(symbolDesc).ToCString();
214 if (str != "method") {
215 return "";
216 }
217 return str + '_' + ToCString(id);
218 }
219
DumpFieldIndexByPGO(int index, pgo::HClassLayoutDesc* desc)220 void LayoutInfo::DumpFieldIndexByPGO(int index, pgo::HClassLayoutDesc* desc)
221 {
222 auto key = GetKey(index);
223 auto attr = GetAttr(index);
224 SetIsPGODumped(index);
225 TrackType type = attr.GetTrackType();
226 int propertyMeta = attr.GetPropertyMetaData();
227 if (key.IsString()) {
228 auto keyString = EcmaStringAccessor(key).ToCString();
229 desc->InsertKeyAndDesc(keyString, PGOHandler(type, propertyMeta, false));
230 } else if (key.IsSymbol()) {
231 auto keyString = GetSymbolKeyString(key);
232 if (keyString.empty()) {
233 return;
234 }
235 desc->InsertKeyAndDesc(keyString, PGOHandler(type, propertyMeta, true));
236 }
237 }
238
UpdateFieldIndexByPGO(int index, pgo::HClassLayoutDesc* desc)239 bool LayoutInfo::UpdateFieldIndexByPGO(int index, pgo::HClassLayoutDesc* desc)
240 {
241 auto key = GetKey(index);
242 auto attr = GetAttr(index);
243 if (attr.IsPGODumped()) {
244 return true;
245 }
246 SetIsPGODumped(index);
247 TrackType type = attr.GetTrackType();
248 int propertyMeta = attr.GetPropertyMetaData();
249 if (key.IsString()) {
250 auto keyString = EcmaStringAccessor(key).ToCString();
251 return desc->UpdateKeyAndDesc(keyString, PGOHandler(type, propertyMeta, false));
252 } else if (key.IsSymbol()) {
253 auto keyString = GetSymbolKeyString(key);
254 if (keyString.empty()) {
255 return false;
256 }
257 return desc->UpdateKeyAndDesc(keyString, PGOHandler(type, propertyMeta, true));
258 }
259 return false;
260 }
261 } // namespace panda::ecmascript
262