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