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