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