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_GLOBAL_ENV_H 17 #define ECMASCRIPT_GLOBAL_ENV_H 18 19 #include "ecmascript/accessor_data.h" 20 #include "ecmascript/base_env.h" 21 #include "ecmascript/js_global_object.h" 22 #include "ecmascript/js_thread.h" 23 #include "ecmascript/global_env_constants-inl.h" 24 #include "ecmascript/js_handle.h" 25 #include "ecmascript/global_env_fields.h" 26 #include "ecmascript/on_heap.h" 27 #include "ecmascript/snapshot/mem/snapshot_env.h" 28 29 namespace panda::ecmascript { 30 class JSThread; 31 class GlobalEnv : public BaseEnv { 32 public: 33 using Field = GlobalEnvField; 34 35 #define GLOBAL_ENV_SLOT(type, name, index) \ 36 static constexpr uint16_t index = static_cast<uint16_t>(GlobalEnvField::index); 37 #define GLOBAL_ENV_SLOT_FILTER_BUILTIN4(ARG1, ARG2, ARG3, Index) \ 38 static constexpr uint16_t Index##_INDEX = static_cast<uint16_t>(GlobalEnvField::Index##_INDEX); 39 #define GLOBAL_ENV_SLOT_FILTER_BUILTIN6(ARG1, ARG2, ARG3, ARG4, ARG5, Index) \ 40 static constexpr uint16_t Index##_INDEX = static_cast<uint16_t>(GlobalEnvField::Index##_INDEX); 41 42 GLOBAL_ENV_FIELDS(GLOBAL_ENV_SLOT) 43 BUILTINS_METHOD_STUB_LIST(GLOBAL_ENV_SLOT_FILTER_BUILTIN4, GLOBAL_ENV_SLOT_FILTER_BUILTIN4, 44 GLOBAL_ENV_SLOT_FILTER_BUILTIN4, GLOBAL_ENV_SLOT_FILTER_BUILTIN6) 45 46 static constexpr uint16_t FIRST_DETECTOR_SYMBOL_INDEX = static_cast<uint16_t>(Field::REPLACE_SYMBOL_INDEX); 47 static constexpr uint16_t LAST_DETECTOR_SYMBOL_INDEX = static_cast<uint16_t>(Field::SPECIES_SYMBOL_INDEX); 48 static constexpr uint16_t FINAL_INDEX = static_cast<uint16_t>(GlobalEnvField::FINAL_INDEX); 49 static constexpr uint8_t RESERVED_LENGTH = 1; // divide the gc area 50 static constexpr uint16_t JSTHREAD_INDEX = FINAL_INDEX; // not need gc 51 #undef GLOBAL_ENV_SLOT 52 GetGlobalObject()53 JSTaggedValue GetGlobalObject() const 54 { 55 return GetJSGlobalObject().GetTaggedValue(); 56 } 57 ComputeObjectAddress(size_t index)58 uintptr_t ComputeObjectAddress(size_t index) const 59 { 60 return reinterpret_cast<uintptr_t>(this) + HEADER_SIZE + index * JSTaggedValue::TaggedTypeSize(); 61 } 62 GetGlobalEnvObjectByIndex(size_t index)63 JSHandle<JSTaggedValue> GetGlobalEnvObjectByIndex(size_t index) const 64 { 65 ASSERT(index < FINAL_INDEX); 66 uintptr_t address = ComputeObjectAddress(index); 67 JSHandle<JSTaggedValue> result(address); 68 return result; 69 } 70 GetNoLazyEnvObjectByIndex(size_t index)71 JSHandle<JSTaggedValue> GetNoLazyEnvObjectByIndex(size_t index) const 72 { 73 JSHandle<JSTaggedValue> result = GetGlobalEnvObjectByIndex(index); 74 if (result->IsInternalAccessor()) { 75 JSThread *thread = GetJSThread(); 76 AccessorData *accessor = AccessorData::Cast(result->GetTaggedObject()); 77 accessor->CallInternalGet(thread, JSHandle<JSObject>::Cast(GetJSGlobalObject())); 78 } 79 return result; 80 } 81 GetGlobalEnvFieldSize()82 size_t GetGlobalEnvFieldSize() const 83 { 84 return FINAL_INDEX; 85 } 86 87 void Init(JSThread *thread); 88 Cast(TaggedObject * object)89 static GlobalEnv *Cast(TaggedObject *object) 90 { 91 ASSERT(JSTaggedValue(object).IsJSGlobalEnv()); 92 return reinterpret_cast<GlobalEnv *>(object); 93 } 94 95 void Iterate(RootVisitor &v); 96 GetJSThread()97 JSThread* GetJSThread() const 98 { 99 uintptr_t address = ComputeObjectAddress(JSTHREAD_INDEX); 100 return *reinterpret_cast<JSThread**>(address); 101 } 102 SetJSThread(JSThread * thread)103 void SetJSThread(JSThread *thread) 104 { 105 uintptr_t address = ComputeObjectAddress(JSTHREAD_INDEX); 106 *reinterpret_cast<JSThread**>(address) = thread; 107 } 108 109 void ClearCache(JSThread *thread) const; 110 111 // For work serialize, add initialized global env object to snapshot env map AddValueToSnapshotEnv(const JSThread * thread,JSTaggedValue value,uint16_t index,uint32_t offset)112 void AddValueToSnapshotEnv(const JSThread *thread, JSTaggedValue value, uint16_t index, uint32_t offset) 113 { 114 if (!value.IsInternalAccessor()) { 115 SnapshotEnv *snapshotEnv = thread->GetEcmaVM()->GetSnapshotEnv(); 116 if (!RemoveValueFromSnapshotEnv(thread, snapshotEnv, value, offset)) { 117 return; 118 } 119 size_t globalConstCount = thread->GlobalConstants()->GetConstantCount(); 120 snapshotEnv->Push(value.GetRawData(), index + globalConstCount); 121 } 122 } 123 124 // For work serialize, remove old value from snapshot env map RemoveValueFromSnapshotEnv(const JSThread * thread,SnapshotEnv * snapshotEnv,JSTaggedValue value,uint32_t offset)125 bool RemoveValueFromSnapshotEnv(const JSThread *thread, SnapshotEnv *snapshotEnv, JSTaggedValue value, 126 uint32_t offset) 127 { 128 JSTaggedValue oldValue(Barriers::GetTaggedValue(thread, this, offset)); 129 if (oldValue == value) { 130 return false; 131 } 132 if (oldValue.IsHeapObject() && !oldValue.IsInternalAccessor()) { 133 // Remove old value 134 snapshotEnv->Remove(oldValue.GetRawData()); 135 } 136 return true; 137 } 138 InitElementKindHClass(const JSThread * thread,JSHandle<JSHClass> originHClass)139 void InitElementKindHClass(const JSThread *thread, JSHandle<JSHClass> originHClass) 140 { 141 { 142 JSHandle<JSHClass> hclass; 143 #define INIT_ARRAY_HCLASS_INDEX_ARRAYS(name) \ 144 hclass = JSHClass::CloneWithElementsKind(thread, originHClass, ElementsKind::name, false); \ 145 this->SetElement##name##Class(thread, hclass); 146 147 ELEMENTS_KIND_INIT_HCLASS_LIST(INIT_ARRAY_HCLASS_INDEX_ARRAYS) 148 #undef INIT_ARRAY_HCLASS_INDEX_ARRAYS 149 } 150 this->SetElementHOLE_TAGGEDClass(thread, originHClass); 151 { 152 JSHandle<JSHClass> hclass; 153 #define INIT_ARRAY_HCLASS_INDEX_ARRAYS(name) \ 154 hclass = JSHClass::CloneWithElementsKind(thread, originHClass, ElementsKind::name, true); \ 155 this->SetElement##name##ProtoClass(thread, hclass); 156 157 ELEMENTS_KIND_INIT_HCLASS_LIST(INIT_ARRAY_HCLASS_INDEX_ARRAYS) 158 #undef INIT_ARRAY_HCLASS_INDEX_ARRAYS 159 } 160 } 161 162 JSHandle<JSTaggedValue> GetSymbol(JSThread *thread, const JSHandle<JSTaggedValue> &string); 163 JSHandle<JSTaggedValue> GetStringFunctionByName(JSThread *thread, const char *name); 164 JSHandle<JSTaggedValue> GetStringPrototypeFunctionByName(JSThread *thread, const char *name); 165 GetFirstDetectorSymbolAddr(const GlobalEnv * env)166 static inline uintptr_t GetFirstDetectorSymbolAddr(const GlobalEnv *env) 167 { 168 constexpr size_t offset = HEADER_SIZE + FIRST_DETECTOR_SYMBOL_INDEX * JSTaggedValue::TaggedTypeSize(); 169 uintptr_t addr = reinterpret_cast<uintptr_t>(env) + offset; 170 return *reinterpret_cast<uintptr_t *>(addr); 171 } 172 GetLastDetectorSymbolAddr(const GlobalEnv * env)173 static uintptr_t GetLastDetectorSymbolAddr(const GlobalEnv *env) 174 { 175 constexpr size_t offset = HEADER_SIZE + LAST_DETECTOR_SYMBOL_INDEX * JSTaggedValue::TaggedTypeSize(); 176 uintptr_t addr = reinterpret_cast<uintptr_t>(env) + offset; 177 return *reinterpret_cast<uintptr_t *>(addr); 178 } 179 IsArrayPrototypeChangedGuardiansInvalid()180 bool IsArrayPrototypeChangedGuardiansInvalid() const 181 { 182 return !GetArrayPrototypeChangedGuardians(); 183 } 184 InitializeGuardians()185 void InitializeGuardians() 186 { 187 SetArrayPrototypeChangedGuardians(true); 188 } 189 190 void NotifyArrayPrototypeChangedGuardians(JSThread *thread, JSHandle<JSObject> receiver); 191 SetBuiltinFunction(const JSThread * thread,kungfu::BuiltinsStubCSigns::ID builtinId,JSHandle<JSFunction> function)192 void SetBuiltinFunction(const JSThread *thread, kungfu::BuiltinsStubCSigns::ID builtinId, 193 JSHandle<JSFunction> function) 194 { 195 ASSERT(builtinId != kungfu::BuiltinsStubCSigns::ID::INVALID); 196 #define SET_BUILTIN_FUNCTION_CASE(type, name, index) \ 197 case kungfu::BuiltinsStubCSigns::ID::name: \ 198 Set##name(thread, function); \ 199 break; 200 #define SET_BUILTIN_METHOD_STUB_IMPL4(name, builtin, unused, index) \ 201 SET_BUILTIN_FUNCTION_CASE(unused, builtin##name, index##_INDEX) 202 #define SET_BUILTIN_METHOD_STUB_IMPL6(name, builtin, Unused0, Unused1, Unused2, index) \ 203 SET_BUILTIN_FUNCTION_CASE(Unused0, builtin##name, index##_INDEX) 204 switch (builtinId) { 205 GLOBAL_ENV_INLINED_BUILTINS(SET_BUILTIN_FUNCTION_CASE) 206 BUILTINS_METHOD_STUB_LIST(SET_BUILTIN_METHOD_STUB_IMPL4, SET_BUILTIN_METHOD_STUB_IMPL4, 207 SET_BUILTIN_METHOD_STUB_IMPL4, SET_BUILTIN_METHOD_STUB_IMPL6) 208 default: 209 LOG_ECMA(FATAL) << "SetBuiltinFunction: invalid builtinId: " << builtinId; 210 UNREACHABLE(); 211 } 212 #undef SET_BUILTIN_METHOD_STUB_IMPL6 213 #undef SET_BUILTIN_METHOD_STUB_IMPL4 214 #undef SET_BUILTIN_FUNCTION_CASE 215 } 216 217 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 218 #define GLOBAL_ENV_FIELD_ACCESSORS(type, name, index) \ 219 inline JSHandle<type> Get##name() const \ 220 { \ 221 size_t offset = HEADER_SIZE + (index)*JSTaggedValue::TaggedTypeSize(); \ 222 const uintptr_t address = reinterpret_cast<uintptr_t>(this) + offset; \ 223 JSHandle<type> result(address); \ 224 if (result.GetTaggedValue().IsInternalAccessor()) { \ 225 JSThread *thread = GetJSThread(); \ 226 AccessorData *accessor = AccessorData::Cast(result.GetTaggedValue().GetTaggedObject()); \ 227 accessor->CallInternalGet(thread, JSHandle<JSObject>::Cast(GetJSGlobalObject())); \ 228 } \ 229 return result; \ 230 } \ 231 inline JSTaggedValue GetTagged##name() const \ 232 { \ 233 uint32_t offset = HEADER_SIZE + index * JSTaggedValue::TaggedTypeSize(); \ 234 JSTaggedValue result(Barriers::GetPrimitive<JSTaggedValue>(this, offset)); \ 235 if (result.IsInternalAccessor()) { \ 236 JSThread *thread = GetJSThread(); \ 237 AccessorData *accessor = AccessorData::Cast(result.GetTaggedObject()); \ 238 accessor->CallInternalGet(thread, JSHandle<JSObject>::Cast(GetJSGlobalObject())); \ 239 } \ 240 return result; \ 241 } \ 242 inline JSHandle<type> GetRaw##name() const \ 243 { \ 244 const uintptr_t address = \ 245 reinterpret_cast<uintptr_t>(this) + HEADER_SIZE + index * JSTaggedValue::TaggedTypeSize(); \ 246 JSHandle<type> result(address); \ 247 return result; \ 248 } \ 249 template<typename T> \ 250 inline void Set##name(const JSThread *thread, JSHandle<T> value, BarrierMode mode = WRITE_BARRIER) \ 251 { \ 252 uint32_t offset = HEADER_SIZE + index * JSTaggedValue::TaggedTypeSize(); \ 253 if (mode == WRITE_BARRIER && value.GetTaggedValue().IsHeapObject()) { \ 254 AddValueToSnapshotEnv(thread, value.GetTaggedValue(), index, offset); \ 255 Barriers::SetObject<true>(thread, this, offset, value.GetTaggedValue().GetRawData()); \ 256 } else { \ 257 SnapshotEnv *snapshotEnv = thread->GetEcmaVM()->GetSnapshotEnv(); \ 258 RemoveValueFromSnapshotEnv(thread, snapshotEnv, value.GetTaggedValue(), offset); \ 259 Barriers::SetPrimitive<JSTaggedType>(this, offset, value.GetTaggedValue().GetRawData()); \ 260 } \ 261 } \ 262 inline void Set##name(const JSThread *thread, type value, BarrierMode mode = WRITE_BARRIER) \ 263 { \ 264 uint32_t offset = HEADER_SIZE + index * JSTaggedValue::TaggedTypeSize(); \ 265 if (mode == WRITE_BARRIER && value.IsHeapObject()) { \ 266 AddValueToSnapshotEnv(thread, value, index, offset); \ 267 Barriers::SetObject<true>(thread, this, offset, value.GetRawData()); \ 268 } else { \ 269 SnapshotEnv *snapshotEnv = thread->GetEcmaVM()->GetSnapshotEnv(); \ 270 RemoveValueFromSnapshotEnv(thread, snapshotEnv, value, offset); \ 271 Barriers::SetPrimitive<JSTaggedType>(this, offset, value.GetRawData()); \ 272 } \ 273 } 274 275 #define GLOBAL_ENV_BUILTIN_ACCESSORS4_IMPL(name, builtin, value, index) \ 276 GLOBAL_ENV_FIELD_ACCESSORS(JSTaggedValue, builtin##name, index##_INDEX) 277 #define GLOBAL_ENV_BUILTIN_ACCESSORS6_IMPL(name, builtin, Unused0, Unused1, Unused2, Index) \ 278 GLOBAL_ENV_FIELD_ACCESSORS(JSTaggedValue, builtin##name, Index##_INDEX) 279 BUILTINS_METHOD_STUB_LIST(GLOBAL_ENV_BUILTIN_ACCESSORS4_IMPL, GLOBAL_ENV_BUILTIN_ACCESSORS4_IMPL, 280 GLOBAL_ENV_BUILTIN_ACCESSORS4_IMPL, GLOBAL_ENV_BUILTIN_ACCESSORS6_IMPL) 281 GLOBAL_ENV_FIELDS(GLOBAL_ENV_FIELD_ACCESSORS) 282 #undef GLOBAL_ENV_BUILTIN_ACCESSORS6_IMPL 283 #undef GLOBAL_ENV_BUILTIN_ACCESSORS4_IMPL 284 #undef GLOBAL_ENV_FIELD_ACCESSORS 285 286 GlobalEnvField GetBuildinTypedArrayHClassIndex(JSType jSType, OnHeapMode mode); 287 GetBuildinTypedArrayHClassByJSType(JSType jSType,OnHeapMode mode)288 inline JSHClass* GetBuildinTypedArrayHClassByJSType(JSType jSType, OnHeapMode mode) 289 { 290 GlobalEnvField buildinTypedArrayHClassIndex = GetBuildinTypedArrayHClassIndex(jSType, mode); 291 if (buildinTypedArrayHClassIndex == GlobalEnvField::INVALID) { 292 return nullptr; 293 } 294 auto index = static_cast<size_t>(buildinTypedArrayHClassIndex); 295 JSHandle<JSTaggedValue> result = GetGlobalEnvObjectByIndex(index); 296 return reinterpret_cast<JSHClass *>(result->GetRawData()); 297 } 298 299 static constexpr size_t HEADER_SIZE = BaseEnv::DATA_OFFSET; 300 static constexpr size_t DATA_SIZE = HEADER_SIZE + FINAL_INDEX * JSTaggedValue::TaggedTypeSize(); 301 static constexpr size_t BIT_FIELD_OFFSET = DATA_SIZE + RESERVED_LENGTH * JSTaggedValue::TaggedTypeSize(); 302 303 ACCESSORS_BIT_FIELD(BitField, BIT_FIELD_OFFSET, LAST_OFFSET) 304 DEFINE_ALIGN_SIZE(LAST_OFFSET); 305 DECL_VISIT_OBJECT(HEADER_SIZE, DATA_SIZE); 306 307 // define BitField 308 static constexpr uint32_t DEFAULT_LAZY_BITFIELD_VALUE = 0x7fe; // 0000'...'0000'0111'1111'1110 309 static constexpr size_t ARRAYPROTOTYPE_CHANGED_GUARDIANS = 1; 310 static constexpr size_t DETECTOR_BITS = 1; FIRST_BIT_FIELD(BitField,ArrayPrototypeChangedGuardians,bool,ARRAYPROTOTYPE_CHANGED_GUARDIANS)311 FIRST_BIT_FIELD(BitField, ArrayPrototypeChangedGuardians, bool, ARRAYPROTOTYPE_CHANGED_GUARDIANS) 312 NEXT_BIT_FIELD(BitField, RegExpReplaceDetector, bool, DETECTOR_BITS, ArrayPrototypeChangedGuardians) 313 NEXT_BIT_FIELD(BitField, MapIteratorDetector, bool, DETECTOR_BITS, RegExpReplaceDetector) 314 NEXT_BIT_FIELD(BitField, SetIteratorDetector, bool, DETECTOR_BITS, MapIteratorDetector) 315 NEXT_BIT_FIELD(BitField, StringIteratorDetector, bool, DETECTOR_BITS, SetIteratorDetector) 316 NEXT_BIT_FIELD(BitField, ArrayIteratorDetector, bool, DETECTOR_BITS, StringIteratorDetector) 317 NEXT_BIT_FIELD(BitField, TypedArrayIteratorDetector, bool, DETECTOR_BITS, ArrayIteratorDetector) 318 NEXT_BIT_FIELD(BitField, TypedArraySpeciesProtectDetector, bool, DETECTOR_BITS, TypedArrayIteratorDetector) 319 NEXT_BIT_FIELD(BitField, NumberStringNotRegexpLikeDetector, bool, DETECTOR_BITS, TypedArraySpeciesProtectDetector) 320 NEXT_BIT_FIELD(BitField, RegExpFlagsDetector, bool, DETECTOR_BITS, NumberStringNotRegexpLikeDetector) 321 NEXT_BIT_FIELD(BitField, RegExpSpeciesDetector, bool, DETECTOR_BITS, RegExpFlagsDetector) 322 NEXT_BIT_FIELD(BitField, LastBitField, bool, DETECTOR_BITS, RegExpSpeciesDetector) 323 324 bool GetDetectorValue(uint32_t detectorID) 325 { 326 ASSERT(detectorID < LastBitFieldBits::START_BIT); 327 uint32_t bitField = GetBitField(); 328 return (bitField >> detectorID) & 1; 329 } 330 HasDependentInfos(JSThread * thread,uint32_t detectorID)331 bool HasDependentInfos(JSThread *thread, uint32_t detectorID) 332 { 333 auto array = JSHandle<TaggedArray>::Cast(GetDetectorDependentInfos()); 334 ASSERT(detectorID < array->GetLength()); 335 return array->Get(thread, detectorID) != JSTaggedValue::Undefined(); 336 } 337 GetDependentInfos(JSThread * thread,uint32_t detectorID)338 JSHandle<JSTaggedValue> GetDependentInfos(JSThread *thread, uint32_t detectorID) 339 { 340 auto array = JSHandle<TaggedArray>::Cast(GetDetectorDependentInfos()); 341 ASSERT(detectorID < array->GetLength()); 342 return JSHandle<JSTaggedValue>(GetJSThread(), array->Get(thread, detectorID)); 343 } 344 SetDependentInfos(uint32_t detectorID,JSHandle<JSTaggedValue> dependentInfos)345 void SetDependentInfos(uint32_t detectorID, JSHandle<JSTaggedValue> dependentInfos) 346 { 347 auto array = JSHandle<TaggedArray>::Cast(GetDetectorDependentInfos()); 348 ASSERT(detectorID < array->GetLength()); 349 array->Set(GetJSThread(), detectorID, dependentInfos); 350 } 351 352 void NotifyDetectorDeoptimize(JSThread *thread, uint32_t detectorID); 353 DECL_DUMP() 354 }; 355 } // namespace panda::ecmascript 356 357 #endif // ECMASCRIPT_GLOBAL_ENV_H 358