1 /* 2 * Copyright (c) 2021-2024 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 #ifndef ECMASCRIPT_OBJECT_OPERATOR_H 17 #define ECMASCRIPT_OBJECT_OPERATOR_H 18 19 #include "ecmascript/js_handle.h" 20 #include "ecmascript/js_object.h" 21 #include "ecmascript/js_thread.h" 22 #include "ecmascript/property_attributes.h" 23 24 #include "ecmascript/ecma_string.h" 25 #include "libpandabase/utils/bit_field.h" 26 27 namespace panda::ecmascript { 28 class PropertyDescriptor; 29 class JSObject; 30 using SCheckMode = JSShared::SCheckMode; 31 32 enum class OperatorType : uint8_t { 33 PROTOTYPE_CHAIN, 34 OWN, 35 }; 36 37 class ObjectOperator final { 38 public: 39 ObjectOperator() = default; 40 41 ObjectOperator(JSThread *thread, const JSHandle<JSTaggedValue> &key, 42 OperatorType type = OperatorType::PROTOTYPE_CHAIN); 43 44 ObjectOperator(JSThread *thread, const JSHandle<JSObject> &holder, const JSHandle<JSTaggedValue> &key, 45 OperatorType type = OperatorType::PROTOTYPE_CHAIN); 46 47 ObjectOperator(JSThread *thread, const JSHandle<JSTaggedValue> &holder, const JSHandle<JSTaggedValue> &key, 48 OperatorType type = OperatorType::PROTOTYPE_CHAIN); 49 50 ObjectOperator(JSThread *thread, const JSHandle<JSTaggedValue> &holder, 51 const JSHandle<JSTaggedValue> &receiver, const JSHandle<JSTaggedValue> &key, 52 OperatorType type = OperatorType::PROTOTYPE_CHAIN); 53 54 ObjectOperator(JSThread *thread, const JSHandle<JSTaggedValue> &holder, uint32_t index, 55 OperatorType type = OperatorType::PROTOTYPE_CHAIN); 56 // op for fast path, name can only string and symbol, and can't be number. 57 ObjectOperator(JSThread *thread, const JSTaggedValue &receiver, const JSTaggedValue &name, 58 OperatorType type = OperatorType::PROTOTYPE_CHAIN); 59 // op for fast add 60 ObjectOperator(JSThread *thread, const JSTaggedValue &receiver, const JSTaggedValue &name, 61 const PropertyAttributes &attr); 62 63 static void FastAdd(JSThread *thread, const JSTaggedValue &receiver, const JSTaggedValue &name, 64 const JSHandle<JSTaggedValue> &value, const PropertyAttributes &attr); 65 66 void UpdateDetector(); 67 static void PUBLIC_API UpdateDetector(const JSThread *thread, JSTaggedValue receiver, JSTaggedValue key); 68 static void UpdateDetectorOnSetPrototype(const JSThread *thread, JSTaggedValue receiver); 69 static bool IsDetectorName(const JSThread *thread, JSTaggedValue key); 70 71 NO_COPY_SEMANTIC(ObjectOperator); 72 DEFAULT_NOEXCEPT_MOVE_SEMANTIC(ObjectOperator); 73 ~ObjectOperator() = default; 74 75 /** 76 * Create ObjectOperator instance by new operator is forbidden, for the member holder is a JSHandle type. it must 77 * be created and destroyed on stack 78 */ 79 void *operator new([[maybe_unused]] size_t t) = delete; 80 void operator delete([[maybe_unused]] void *ptr) = delete; 81 IsFound()82 inline bool IsFound() const 83 { 84 return index_ != NOT_FOUND_INDEX; 85 } 86 IsFastMode()87 inline bool IsFastMode() const 88 { 89 return IsFastModeField::Get(metaData_); 90 } 91 SetFastMode(bool flag)92 inline void SetFastMode(bool flag) 93 { 94 IsFastModeField::Set(flag, &metaData_); 95 } 96 SetFoundDict(bool flag)97 inline void SetFoundDict(bool flag) 98 { 99 IsFoundDictField::Set(flag, &metaData_); 100 } 101 IsFoundDict()102 inline bool IsFoundDict() const 103 { 104 return IsFoundDictField::Get(metaData_); 105 } 106 IsElement()107 inline bool IsElement() const 108 { 109 return key_.IsEmpty(); 110 } 111 GetThroughElement()112 inline bool GetThroughElement() const 113 { 114 uint32_t len = EcmaStringAccessor(holder_->GetTaggedObject()).GetLength(); 115 bool flag = elementIndex_ < len; 116 return key_.IsEmpty() && flag; 117 } 118 GetStringLength()119 inline bool GetStringLength() const 120 { 121 JSTaggedValue lenKey = thread_->GlobalConstants()->GetLengthString(); 122 if (GetKey()->IsUndefined() || !GetKey()->IsString()) { 123 return false; 124 } 125 EcmaString *proKey = EcmaString::Cast(GetKey()->GetTaggedObject()); 126 return receiver_->IsString() && EcmaStringAccessor::StringsAreEqual(proKey, 127 EcmaString::Cast(lenKey.GetTaggedObject())); 128 } 129 IsOnPrototype()130 inline bool IsOnPrototype() const 131 { 132 return IsOnPrototypeField::Get(metaData_); 133 } 134 SetIsOnPrototype(bool flag)135 inline void SetIsOnPrototype(bool flag) 136 { 137 IsOnPrototypeField::Set(flag, &metaData_); 138 } 139 HasReceiver()140 inline bool HasReceiver() const 141 { 142 return HasReceiverField::Get(metaData_); 143 } 144 SetHasReceiver(bool flag)145 inline void SetHasReceiver(bool flag) 146 { 147 HasReceiverField::Set(flag, &metaData_); 148 } 149 IsTransition()150 inline bool IsTransition() const 151 { 152 return IsTransitionField::Get(metaData_); 153 } 154 SetIsTransition(bool flag)155 inline void SetIsTransition(bool flag) 156 { 157 IsTransitionField::Set(flag, &metaData_); 158 } 159 IsTSHClass()160 inline bool IsTSHClass() const 161 { 162 return IsTSHClassField::Get(metaData_); 163 } 164 SetIsTSHClass(bool flag)165 inline void SetIsTSHClass(bool flag) 166 { 167 IsTSHClassField::Set(flag, &metaData_); 168 } 169 GetAttr()170 inline PropertyAttributes GetAttr() const 171 { 172 return attributes_; 173 } 174 SetAttr(uint64_t attr)175 inline void SetAttr(uint64_t attr) 176 { 177 attributes_ = PropertyAttributes(attr); 178 } 179 SetAttr(const PropertyAttributes & attr)180 inline void SetAttr(const PropertyAttributes &attr) 181 { 182 attributes_ = attr; 183 } 184 IsPrimitiveAttr()185 inline bool IsPrimitiveAttr() const 186 { 187 return !attributes_.GetValue(); 188 } 189 IsWritable()190 inline bool IsWritable() const 191 { 192 return GetAttr().IsWritable(); 193 } 194 IsEnumerable()195 inline bool IsEnumerable() const 196 { 197 return GetAttr().IsEnumerable(); 198 } 199 IsConfigurable()200 inline bool IsConfigurable() const 201 { 202 return GetAttr().IsConfigurable(); 203 } 204 IsAccessorDescriptor()205 inline bool IsAccessorDescriptor() const 206 { 207 return GetAttr().IsAccessor(); 208 } 209 IsInlinedProps()210 inline bool IsInlinedProps() const 211 { 212 return GetAttr().IsInlinedProps(); 213 } 214 SetIsInlinedProps(bool flag)215 inline void SetIsInlinedProps(bool flag) 216 { 217 attributes_.SetIsInlinedProps(flag); 218 } 219 GetRepresentation()220 inline Representation GetRepresentation() const 221 { 222 return GetAttr().GetRepresentation(); 223 } 224 GetValue()225 inline JSTaggedValue GetValue() const 226 { 227 if (value_.IsEmpty()) { 228 return JSTaggedValue::Undefined(); 229 } 230 return value_.GetTaggedValue(); 231 } 232 233 JSHandle<JSTaggedValue> FastGetValue(); SetValue(JSTaggedValue value)234 inline void SetValue(JSTaggedValue value) 235 { 236 if (value_.IsEmpty()) { 237 value_ = JSMutableHandle<JSTaggedValue>(thread_, value); 238 } 239 value_.Update(value); 240 } 241 SetIndex(uint32_t index)242 inline void SetIndex(uint32_t index) 243 { 244 index_ = index; 245 } 246 GetIndex()247 inline uint32_t GetIndex() const 248 { 249 return index_; 250 } 251 SetElementOutOfBounds(bool val)252 inline void SetElementOutOfBounds(bool val) 253 { 254 elementsOutOfBounds_ = val; 255 } 256 GetElementOutOfBounds()257 inline bool GetElementOutOfBounds() const 258 { 259 return elementsOutOfBounds_; 260 } 261 HasHolder()262 inline bool HasHolder() const 263 { 264 return !holder_.IsEmpty(); 265 } 266 GetHolder()267 inline JSHandle<JSTaggedValue> GetHolder() const 268 { 269 return holder_; 270 } 271 GetReceiver()272 inline JSHandle<JSTaggedValue> GetReceiver() const 273 { 274 return receiver_; 275 } 276 GetKey()277 inline JSHandle<JSTaggedValue> GetKey() const 278 { 279 if (key_.IsEmpty()) { 280 return JSHandle<JSTaggedValue>(thread_, JSTaggedValue::Undefined()); 281 } 282 return key_; 283 } 284 KeyFromStringType()285 inline bool KeyFromStringType() const 286 { 287 return keyFromStringType_; 288 } 289 GetElementIndex()290 inline uint32_t GetElementIndex() const 291 { 292 return elementIndex_; 293 } 294 GetThread()295 inline JSThread *GetThread() const 296 { 297 return thread_; 298 } 299 300 void ToPropertyDescriptor(PropertyDescriptor &desc) const; 301 SharedFieldType GetSharedFieldType() const; 302 void LookupProperty(); 303 void GlobalLookupProperty(); ReLookupPropertyInReceiver()304 inline void ReLookupPropertyInReceiver() 305 { 306 ResetState(); 307 return LookupPropertyInlinedProps(JSHandle<JSObject>(receiver_)); 308 } SetAsDefaultAttr()309 inline void SetAsDefaultAttr() 310 { 311 SetFound(NOT_FOUND_INDEX, JSTaggedValue::Undefined(), PropertyAttributes::GetDefaultAttributes(), false, false); 312 } 313 bool UpdateDataValue(const JSHandle<JSObject> &receiver, const JSHandle<JSTaggedValue> &value, 314 bool isInternalAccessor, bool mayThrow = false); WriteDataPropertyInHolder(const PropertyDescriptor & desc)315 bool WriteDataPropertyInHolder(const PropertyDescriptor &desc) 316 { 317 JSHandle<JSObject> receiver(holder_); 318 return WriteDataProperty(receiver, desc); 319 } 320 bool WriteDataProperty(const JSHandle<JSObject> &receiver, const PropertyDescriptor &desc); 321 bool AddProperty(const JSHandle<JSObject> &receiver, const JSHandle<JSTaggedValue> &value, PropertyAttributes attr); AddPropertyInHolder(const JSHandle<JSTaggedValue> & value,PropertyAttributes attr)322 inline bool AddPropertyInHolder(const JSHandle<JSTaggedValue> &value, PropertyAttributes attr) 323 { 324 JSHandle<JSObject> obj(holder_); 325 return AddProperty(obj, value, attr); 326 } 327 void DeletePropertyInHolder(); 328 static constexpr uint32_t NOT_FOUND_INDEX = std::numeric_limits<uint32_t>::max(); 329 static JSTaggedValue ToHolder(const JSHandle<JSTaggedValue> &holder); 330 void AddPropertyInternal(const JSHandle<JSTaggedValue> &value); 331 void DefineSetter(const JSHandle<JSTaggedValue> &value); 332 void DefineGetter(const JSHandle<JSTaggedValue> &value); 333 334 private: 335 static constexpr uint64_t ATTR_LENGTH = 5; 336 static constexpr uint64_t INDEX_LENGTH = 32; 337 338 using IsFastModeField = BitField<bool, 0, 1>; 339 using IsOnPrototypeField = IsFastModeField::NextFlag; // 1: on prototype 340 using HasReceiverField = IsOnPrototypeField::NextFlag; 341 using IsTransitionField = HasReceiverField::NextFlag; 342 using IsTSHClassField = IsTransitionField::NextFlag; 343 // found dictionary obj between receriver and holder 344 using IsFoundDictField = IsTSHClassField::NextFlag; 345 346 void UpdateHolder(); 347 void UpdateIsTSHClass(); 348 void StartLookUp(OperatorType type); 349 void StartGlobalLookUp(OperatorType type); 350 void HandleKey(const JSHandle<JSTaggedValue> &key); 351 uint32_t ComputeElementCapacity(uint32_t oldCapacity); 352 void SetFound(uint32_t index, JSTaggedValue value, uint64_t attr, bool mode, bool transition = false); 353 void UpdateFound(uint32_t index, uint64_t attr, bool mode, bool transition); 354 void ResetState(); 355 void ResetStateForAddProperty(); LookupPropertyInHolder()356 inline void LookupPropertyInHolder() 357 { 358 JSHandle<JSObject> obj(holder_); 359 LookupPropertyInlinedProps(obj); 360 } GlobalLookupPropertyInHolder()361 inline void GlobalLookupPropertyInHolder() 362 { 363 JSHandle<JSObject> obj(holder_); 364 LookupGlobal(obj); 365 } 366 void LookupGlobal(const JSHandle<JSObject> &obj); 367 void LookupPropertyInlinedProps(const JSHandle<JSObject> &obj); 368 void LookupElementInlinedProps(const JSHandle<JSObject> &obj); 369 void WriteElement(const JSHandle<JSObject> &receiver, const PropertyDescriptor &desc); 370 void WriteElement(const JSHandle<JSObject> &receiver, JSHandle<JSTaggedValue> value) const; 371 void DeleteElementInHolder() const; 372 bool UpdateValueAndDetails(const JSHandle<JSObject> &receiver, const JSHandle<JSTaggedValue> &value, 373 PropertyAttributes attr, bool attrChanged); 374 void TransitionForAttributeChanged(const JSHandle<JSObject> &receiver, PropertyAttributes attr); 375 JSThread *thread_{nullptr}; 376 JSMutableHandle<JSTaggedValue> value_{}; 377 JSMutableHandle<JSTaggedValue> holder_{}; 378 JSMutableHandle<JSTaggedValue> receiver_{}; 379 JSHandle<JSTaggedValue> key_{}; 380 uint32_t elementIndex_{NOT_FOUND_INDEX}; 381 uint32_t index_{NOT_FOUND_INDEX}; 382 PropertyAttributes attributes_; 383 uint32_t metaData_{0}; 384 int receiverHoleEntry_{-1}; 385 bool keyFromStringType_{false}; 386 bool elementsOutOfBounds_{false}; 387 }; 388 } // namespace panda::ecmascript 389 #endif // ECMASCRIPT_OBJECT_OPERATOR_H 390