• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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