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 19namespace panda::ecmascript { 20using PGOHandler = pgo::PGOHandler; 21void 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 31void 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} 61void 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 103void 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 114std::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 136void 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 167void 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 188bool 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 199CString 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 220void 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 239bool 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