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