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/js_global_object.h" 21 #include "ecmascript/js_thread.h" 22 #include "ecmascript/global_env_constants-inl.h" 23 #include "ecmascript/js_handle.h" 24 #include "ecmascript/global_env_fields.h" 25 #include "ecmascript/snapshot/mem/snapshot_env.h" 26 27 namespace panda::ecmascript { 28 class JSThread; 29 class GlobalEnv : public TaggedObject { 30 public: 31 using Field = GlobalEnvField; 32 33 #define GLOBAL_ENV_SLOT(type, name, index) \ 34 static constexpr uint16_t index = static_cast<uint16_t>(GlobalEnvField::index); 35 36 GLOBAL_ENV_FIELDS(GLOBAL_ENV_SLOT) 37 static constexpr uint16_t FIRST_DETECTOR_SYMBOL_INDEX = static_cast<uint16_t>(Field::REPLACE_SYMBOL_INDEX); 38 static constexpr uint16_t LAST_DETECTOR_SYMBOL_INDEX = static_cast<uint16_t>(Field::SPECIES_SYMBOL_INDEX); 39 static constexpr uint16_t FINAL_INDEX = static_cast<uint16_t>(GlobalEnvField::FINAL_INDEX); 40 static constexpr uint8_t RESERVED_LENGTH = 1; // divide the gc area 41 static constexpr uint16_t JSTHREAD_INDEX = FINAL_INDEX; // not need gc 42 #undef GLOBAL_ENV_SLOT 43 GetGlobalObject() const44 JSTaggedValue GetGlobalObject() const 45 { 46 return GetJSGlobalObject().GetTaggedValue(); 47 } 48 ComputeObjectAddress(size_t index) const49 uintptr_t ComputeObjectAddress(size_t index) const 50 { 51 return reinterpret_cast<uintptr_t>(this) + HEADER_SIZE + index * JSTaggedValue::TaggedTypeSize(); 52 } 53 GetGlobalEnvObjectByIndex(size_t index) const54 JSHandle<JSTaggedValue> GetGlobalEnvObjectByIndex(size_t index) const 55 { 56 ASSERT(index < FINAL_INDEX); 57 uintptr_t address = ComputeObjectAddress(index); 58 JSHandle<JSTaggedValue> result(address); 59 return result; 60 } 61 62 JSHandle<JSTaggedValue> GetNoLazyEnvObjectByIndex(size_t index) const 63 { 64 JSHandle<JSTaggedValue> result = GetGlobalEnvObjectByIndex(index); IsInternalAccessor()65 if (result->IsInternalAccessor()) { 66 JSThread *thread = GetJSThread(); 67 AccessorData *accessor = AccessorData::Cast(result->GetTaggedObject()); 68 accessor->CallInternalGet(thread, JSHandle<JSObject>::Cast(GetJSGlobalObject())); 69 } 70 return result; 71 } 72 GetGlobalEnvFieldSize() const73 size_t GetGlobalEnvFieldSize() const 74 { 75 return FINAL_INDEX; 76 } 77 78 void Init(JSThread *thread); 79 Cast(TaggedObject *object)80 static GlobalEnv *Cast(TaggedObject *object) 81 { 82 ASSERT(JSTaggedValue(object).IsJSGlobalEnv()); 83 return reinterpret_cast<GlobalEnv *>(object); 84 } 85 GetJSThread() const86 JSThread* GetJSThread() const 87 { 88 uintptr_t address = ComputeObjectAddress(JSTHREAD_INDEX); 89 return *reinterpret_cast<JSThread**>(address); 90 } 91 SetJSThread(JSThread *thread)92 void SetJSThread(JSThread *thread) 93 { 94 uintptr_t address = ComputeObjectAddress(JSTHREAD_INDEX); 95 *reinterpret_cast<JSThread**>(address) = thread; 96 } 97 98 // For work serialize, add initialized global env object to snapshot env map AddValueToSnapshotEnv(const JSThread *thread, JSTaggedValue value, uint16_t index, uint32_t offset)99 void AddValueToSnapshotEnv(const JSThread *thread, JSTaggedValue value, uint16_t index, uint32_t offset) 100 { 101 if (!value.IsInternalAccessor()) { 102 SnapshotEnv *snapshotEnv = thread->GetEcmaVM()->GetSnapshotEnv(); 103 if (!RemoveValueFromSnapshotEnv(snapshotEnv, value, offset)) { 104 return; 105 } 106 size_t globalConstCount = thread->GlobalConstants()->GetConstantCount(); 107 snapshotEnv->Push(value.GetRawData(), index + globalConstCount); 108 } 109 } 110 111 // For work serialize, remove old value from snapshot env map RemoveValueFromSnapshotEnv(SnapshotEnv *snapshotEnv, JSTaggedValue value, uint32_t offset)112 bool RemoveValueFromSnapshotEnv(SnapshotEnv *snapshotEnv, JSTaggedValue value, uint32_t offset) 113 { 114 JSTaggedValue oldValue(Barriers::GetValue<JSTaggedType>(this, offset)); 115 if (oldValue == value) { 116 return false; 117 } 118 if (oldValue.IsHeapObject() && !oldValue.IsInternalAccessor()) { 119 // Remove old value 120 snapshotEnv->Remove(oldValue.GetRawData()); 121 } 122 return true; 123 } 124 125 JSHandle<JSTaggedValue> GetSymbol(JSThread *thread, const JSHandle<JSTaggedValue> &string); 126 JSHandle<JSTaggedValue> GetStringFunctionByName(JSThread *thread, const char *name); 127 JSHandle<JSTaggedValue> GetStringPrototypeFunctionByName(JSThread *thread, const char *name); 128 GetFirstDetectorSymbolAddr(const GlobalEnv *env)129 static inline uintptr_t GetFirstDetectorSymbolAddr(const GlobalEnv *env) 130 { 131 constexpr size_t offset = HEADER_SIZE + FIRST_DETECTOR_SYMBOL_INDEX * JSTaggedValue::TaggedTypeSize(); 132 uintptr_t addr = reinterpret_cast<uintptr_t>(env) + offset; 133 return *reinterpret_cast<uintptr_t *>(addr); 134 } 135 GetLastDetectorSymbolAddr(const GlobalEnv *env)136 static uintptr_t GetLastDetectorSymbolAddr(const GlobalEnv *env) 137 { 138 constexpr size_t offset = HEADER_SIZE + LAST_DETECTOR_SYMBOL_INDEX * JSTaggedValue::TaggedTypeSize(); 139 uintptr_t addr = reinterpret_cast<uintptr_t>(env) + offset; 140 return *reinterpret_cast<uintptr_t *>(addr); 141 } 142 143 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 144 #define GLOBAL_ENV_FIELD_ACCESSORS(type, name, index) \ 145 inline JSHandle<type> Get##name() const \ 146 { \ 147 const uintptr_t address = \ 148 reinterpret_cast<uintptr_t>(this) + HEADER_SIZE + index * JSTaggedValue::TaggedTypeSize(); \ 149 JSHandle<type> result(address); \ 150 if (result.GetTaggedValue().IsInternalAccessor()) { \ 151 JSThread *thread = GetJSThread(); \ 152 AccessorData *accessor = AccessorData::Cast(result.GetTaggedValue().GetTaggedObject()); \ 153 accessor->CallInternalGet(thread, JSHandle<JSObject>::Cast(GetJSGlobalObject())); \ 154 } \ 155 return result; \ 156 } \ 157 inline JSTaggedValue GetTagged##name() const \ 158 { \ 159 uint32_t offset = HEADER_SIZE + index * JSTaggedValue::TaggedTypeSize(); \ 160 JSTaggedValue result(Barriers::GetValue<JSTaggedType>(this, offset)); \ 161 if (result.IsInternalAccessor()) { \ 162 JSThread *thread = GetJSThread(); \ 163 AccessorData *accessor = AccessorData::Cast(result.GetTaggedObject()); \ 164 accessor->CallInternalGet(thread, JSHandle<JSObject>::Cast(GetJSGlobalObject())); \ 165 } \ 166 return result; \ 167 } \ 168 inline JSHandle<type> GetRaw##name() const \ 169 { \ 170 const uintptr_t address = \ 171 reinterpret_cast<uintptr_t>(this) + HEADER_SIZE + index * JSTaggedValue::TaggedTypeSize(); \ 172 JSHandle<type> result(address); \ 173 return result; \ 174 } \ 175 template<typename T> \ 176 inline void Set##name(const JSThread *thread, JSHandle<T> value, BarrierMode mode = WRITE_BARRIER) \ 177 { \ 178 uint32_t offset = HEADER_SIZE + index * JSTaggedValue::TaggedTypeSize(); \ 179 if (mode == WRITE_BARRIER && value.GetTaggedValue().IsHeapObject()) { \ 180 AddValueToSnapshotEnv(thread, value.GetTaggedValue(), index, offset); \ 181 Barriers::SetObject<true>(thread, this, offset, value.GetTaggedValue().GetRawData()); \ 182 } else { \ 183 SnapshotEnv *snapshotEnv = thread->GetEcmaVM()->GetSnapshotEnv(); \ 184 RemoveValueFromSnapshotEnv(snapshotEnv, value.GetTaggedValue(), offset); \ 185 Barriers::SetPrimitive<JSTaggedType>(this, offset, value.GetTaggedValue().GetRawData()); \ 186 } \ 187 } \ 188 inline void Set##name(const JSThread *thread, type value, BarrierMode mode = WRITE_BARRIER) \ 189 { \ 190 uint32_t offset = HEADER_SIZE + index * JSTaggedValue::TaggedTypeSize(); \ 191 if (mode == WRITE_BARRIER && value.IsHeapObject()) { \ 192 AddValueToSnapshotEnv(thread, value, index, offset); \ 193 Barriers::SetObject<true>(thread, this, offset, value.GetRawData()); \ 194 } else { \ 195 SnapshotEnv *snapshotEnv = thread->GetEcmaVM()->GetSnapshotEnv(); \ 196 RemoveValueFromSnapshotEnv(snapshotEnv, value, offset); \ 197 Barriers::SetPrimitive<JSTaggedType>(this, offset, value.GetRawData()); \ 198 } \ 199 } 200 GLOBAL_ENV_FIELDS(GLOBAL_ENV_FIELD_ACCESSORS) 201 #undef GLOBAL_ENV_FIELD_ACCESSORS 202 203 static constexpr size_t HEADER_SIZE = TaggedObjectSize(); 204 static constexpr size_t DATA_SIZE = HEADER_SIZE + FINAL_INDEX * JSTaggedValue::TaggedTypeSize(); 205 static constexpr size_t SIZE = DATA_SIZE + RESERVED_LENGTH * JSTaggedValue::TaggedTypeSize(); 206 207 DECL_VISIT_OBJECT(HEADER_SIZE, DATA_SIZE); 208 209 DECL_DUMP() 210 }; 211 } // namespace panda::ecmascript 212 213 #endif // ECMASCRIPT_GLOBAL_ENV_H 214