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