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 explicit ObjectOperator() = default; 36 37 explicit ObjectOperator(JSThread *thread, const JSHandle<JSTaggedValue> &key, 38 OperatorType type = OperatorType::PROTOTYPE_CHAIN); 39 40 explicit ObjectOperator(JSThread *thread, const JSHandle<JSObject> &holder, const JSHandle<JSTaggedValue> &key, 41 OperatorType type = OperatorType::PROTOTYPE_CHAIN); 42 43 explicit ObjectOperator(JSThread *thread, const JSHandle<JSTaggedValue> &holder, const JSHandle<JSTaggedValue> &key, 44 OperatorType type = OperatorType::PROTOTYPE_CHAIN); 45 46 explicit ObjectOperator(JSThread *thread, const JSHandle<JSTaggedValue> &holder, 47 const JSHandle<JSTaggedValue> &receiver, const JSHandle<JSTaggedValue> &key, 48 OperatorType type = OperatorType::PROTOTYPE_CHAIN); 49 50 explicit 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 explicit ObjectOperator(JSThread *thread, const JSTaggedValue &receiver, const JSTaggedValue &name, 54 OperatorType type = OperatorType::PROTOTYPE_CHAIN); 55 // op for fast add 56 explicit 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 GetValue()183 inline JSTaggedValue GetValue() const 184 { 185 if (value_.IsEmpty()) { 186 return JSTaggedValue::Undefined(); 187 } 188 return value_.GetTaggedValue(); 189 } 190 191 JSHandle<JSTaggedValue> FastGetValue(); SetValue(JSTaggedValue value)192 inline void SetValue(JSTaggedValue value) 193 { 194 if (value_.IsEmpty()) { 195 value_ = JSMutableHandle<JSTaggedValue>(thread_, value); 196 } 197 value_.Update(value); 198 } 199 SetIndex(uint32_t index)200 inline void SetIndex(uint32_t index) 201 { 202 index_ = index; 203 } 204 GetIndex()205 inline uint32_t GetIndex() const 206 { 207 return index_; 208 } 209 HasHolder()210 inline bool HasHolder() const 211 { 212 return !holder_.IsEmpty(); 213 } 214 GetHolder()215 inline JSHandle<JSTaggedValue> GetHolder() const 216 { 217 return holder_; 218 } 219 GetReceiver()220 inline JSHandle<JSTaggedValue> GetReceiver() const 221 { 222 return receiver_; 223 } 224 GetKey()225 inline JSHandle<JSTaggedValue> GetKey() const 226 { 227 if (key_.IsEmpty()) { 228 return JSHandle<JSTaggedValue>(thread_, JSTaggedValue::Undefined()); 229 } 230 return key_; 231 } 232 GetElementIndex()233 inline uint32_t GetElementIndex() const 234 { 235 return elementIndex_; 236 } 237 GetThread()238 inline JSThread *GetThread() const 239 { 240 return thread_; 241 } 242 243 void ToPropertyDescriptor(PropertyDescriptor &desc) const; 244 void LookupProperty(); 245 void GlobalLookupProperty(); ReLookupPropertyInReceiver()246 inline void ReLookupPropertyInReceiver() 247 { 248 ResetState(); 249 return LookupPropertyInlinedProps(JSHandle<JSObject>(receiver_)); 250 } SetAsDefaultAttr()251 inline void SetAsDefaultAttr() 252 { 253 SetFound(NOT_FOUND_INDEX, JSTaggedValue::Undefined(), PropertyAttributes::GetDefaultAttributes(), false, false); 254 } 255 bool UpdateDataValue(const JSHandle<JSObject> &receiver, const JSHandle<JSTaggedValue> &value, 256 bool isInternalAccessor, bool mayThrow = false); WriteDataPropertyInHolder(const PropertyDescriptor & desc)257 bool WriteDataPropertyInHolder(const PropertyDescriptor &desc) 258 { 259 JSHandle<JSObject> receiver(holder_); 260 return WriteDataProperty(receiver, desc); 261 } 262 bool WriteDataProperty(const JSHandle<JSObject> &receiver, const PropertyDescriptor &desc); 263 bool AddProperty(const JSHandle<JSObject> &receiver, const JSHandle<JSTaggedValue> &value, PropertyAttributes attr); AddPropertyInHolder(const JSHandle<JSTaggedValue> & value,PropertyAttributes attr)264 inline bool AddPropertyInHolder(const JSHandle<JSTaggedValue> &value, PropertyAttributes attr) 265 { 266 JSHandle<JSObject> obj(holder_); 267 return AddProperty(obj, value, attr); 268 } 269 void DeletePropertyInHolder(); 270 static constexpr uint32_t NOT_FOUND_INDEX = std::numeric_limits<uint32_t>::max(); 271 static JSTaggedValue ToHolder(const JSHandle<JSTaggedValue> &holder); 272 void AddPropertyInternal(const JSHandle<JSTaggedValue> &value); 273 void DefineSetter(const JSHandle<JSTaggedValue> &value); 274 void DefineGetter(const JSHandle<JSTaggedValue> &value); 275 276 private: 277 static constexpr uint64_t ATTR_LENGTH = 5; 278 static constexpr uint64_t INDEX_LENGTH = 32; 279 280 using IsFastModeField = BitField<bool, 0, 1>; 281 using IsOnPrototypeField = IsFastModeField::NextFlag; // 1: on prototype 282 using HasReceiverField = IsOnPrototypeField::NextFlag; 283 using IsTransitionField = HasReceiverField::NextFlag; 284 using IsTSHClassField = IsTransitionField::NextFlag; 285 286 void UpdateHolder(); 287 void UpdateIsTSHClass(); 288 void StartLookUp(OperatorType type); 289 void StartGlobalLookUp(OperatorType type); 290 void HandleKey(const JSHandle<JSTaggedValue> &key); 291 uint32_t ComputeElementCapacity(uint32_t oldCapacity); 292 void SetFound(uint32_t index, JSTaggedValue value, uint32_t attr, bool mode, bool transition = false); 293 void UpdateFound(uint32_t index, uint32_t attr, bool mode, bool transition); 294 void ResetState(); 295 void ResetStateForAddProperty(); LookupPropertyInHolder()296 inline void LookupPropertyInHolder() 297 { 298 JSHandle<JSObject> obj(holder_); 299 LookupPropertyInlinedProps(obj); 300 } GlobalLookupPropertyInHolder()301 inline void GlobalLookupPropertyInHolder() 302 { 303 JSHandle<JSObject> obj(holder_); 304 LookupGlobal(obj); 305 } 306 void LookupGlobal(const JSHandle<JSObject> &obj); 307 void LookupPropertyInlinedProps(const JSHandle<JSObject> &obj); 308 void LookupElementInlinedProps(const JSHandle<JSObject> &obj); 309 void WriteElement(const JSHandle<JSObject> &receiver, const PropertyDescriptor &desc); 310 void WriteElement(const JSHandle<JSObject> &receiver, JSTaggedValue value) const; 311 void DeleteElementInHolder() const; 312 bool UpdateValueAndDetails(const JSHandle<JSObject> &receiver, const JSHandle<JSTaggedValue> &value, 313 PropertyAttributes attr, bool attrChanged); 314 void TransitionForAttributeChanged(const JSHandle<JSObject> &receiver, PropertyAttributes attr); 315 JSThread *thread_{nullptr}; 316 JSMutableHandle<JSTaggedValue> value_{}; 317 JSMutableHandle<JSTaggedValue> holder_{}; 318 JSMutableHandle<JSTaggedValue> receiver_{}; 319 JSHandle<JSTaggedValue> key_{}; 320 uint32_t elementIndex_{NOT_FOUND_INDEX}; 321 uint32_t index_{NOT_FOUND_INDEX}; 322 PropertyAttributes attributes_; 323 uint32_t metaData_{0}; 324 int receiverHoleEntry_{-1}; 325 }; 326 } // namespace panda::ecmascript 327 #endif // ECMASCRIPT_OBJECT_OPERATOR_H 328